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>
17*5f7ddb14SDimitry Andric #include <cstdint>
18*5f7ddb14SDimitry 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 
36*5f7ddb14SDimitry 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)450b57cec5SDimitry Andric void StringList::AppendString(std::string &&s) { m_strings.push_back(s); }
460b57cec5SDimitry Andric 
AppendString(const char * str,size_t str_len)470b57cec5SDimitry Andric void StringList::AppendString(const char *str, size_t str_len) {
480b57cec5SDimitry Andric   if (str)
490b57cec5SDimitry Andric     m_strings.push_back(std::string(str, str_len));
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
AppendString(llvm::StringRef str)520b57cec5SDimitry Andric void StringList::AppendString(llvm::StringRef str) {
530b57cec5SDimitry Andric   m_strings.push_back(str.str());
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
AppendList(const char ** strv,int strc)560b57cec5SDimitry Andric void StringList::AppendList(const char **strv, int strc) {
570b57cec5SDimitry Andric   for (int i = 0; i < strc; ++i) {
580b57cec5SDimitry Andric     if (strv[i])
590b57cec5SDimitry Andric       m_strings.push_back(strv[i]);
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
AppendList(StringList strings)630b57cec5SDimitry Andric void StringList::AppendList(StringList strings) {
649dba64beSDimitry Andric   m_strings.reserve(m_strings.size() + strings.GetSize());
659dba64beSDimitry Andric   m_strings.insert(m_strings.end(), strings.begin(), strings.end());
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
GetSize() const680b57cec5SDimitry Andric size_t StringList::GetSize() const { return m_strings.size(); }
690b57cec5SDimitry Andric 
GetMaxStringLength() const700b57cec5SDimitry Andric size_t StringList::GetMaxStringLength() const {
710b57cec5SDimitry Andric   size_t max_length = 0;
720b57cec5SDimitry Andric   for (const auto &s : m_strings) {
730b57cec5SDimitry Andric     const size_t len = s.size();
740b57cec5SDimitry Andric     if (max_length < len)
750b57cec5SDimitry Andric       max_length = len;
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric   return max_length;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
GetStringAtIndex(size_t idx) const800b57cec5SDimitry Andric const char *StringList::GetStringAtIndex(size_t idx) const {
810b57cec5SDimitry Andric   if (idx < m_strings.size())
820b57cec5SDimitry Andric     return m_strings[idx].c_str();
830b57cec5SDimitry Andric   return nullptr;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
Join(const char * separator,Stream & strm)860b57cec5SDimitry Andric void StringList::Join(const char *separator, Stream &strm) {
870b57cec5SDimitry Andric   size_t size = GetSize();
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   if (size == 0)
900b57cec5SDimitry Andric     return;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   for (uint32_t i = 0; i < size; ++i) {
930b57cec5SDimitry Andric     if (i > 0)
940b57cec5SDimitry Andric       strm.PutCString(separator);
950b57cec5SDimitry Andric     strm.PutCString(GetStringAtIndex(i));
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
Clear()990b57cec5SDimitry Andric void StringList::Clear() { m_strings.clear(); }
1000b57cec5SDimitry Andric 
LongestCommonPrefix()1019dba64beSDimitry Andric std::string StringList::LongestCommonPrefix() {
1020b57cec5SDimitry Andric   if (m_strings.empty())
1039dba64beSDimitry Andric     return {};
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   auto args = llvm::makeArrayRef(m_strings);
1060b57cec5SDimitry Andric   llvm::StringRef prefix = args.front();
1070b57cec5SDimitry Andric   for (auto arg : args.drop_front()) {
1080b57cec5SDimitry Andric     size_t count = 0;
1090b57cec5SDimitry Andric     for (count = 0; count < std::min(prefix.size(), arg.size()); ++count) {
1100b57cec5SDimitry Andric       if (prefix[count] != arg[count])
1110b57cec5SDimitry Andric         break;
1120b57cec5SDimitry Andric     }
1130b57cec5SDimitry Andric     prefix = prefix.take_front(count);
1140b57cec5SDimitry Andric   }
1159dba64beSDimitry Andric   return prefix.str();
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
InsertStringAtIndex(size_t idx,const char * str)1180b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, const char *str) {
1190b57cec5SDimitry Andric   if (str) {
1200b57cec5SDimitry Andric     if (idx < m_strings.size())
1210b57cec5SDimitry Andric       m_strings.insert(m_strings.begin() + idx, str);
1220b57cec5SDimitry Andric     else
1230b57cec5SDimitry Andric       m_strings.push_back(str);
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
InsertStringAtIndex(size_t idx,const std::string & str)1270b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, const std::string &str) {
1280b57cec5SDimitry Andric   if (idx < m_strings.size())
1290b57cec5SDimitry Andric     m_strings.insert(m_strings.begin() + idx, str);
1300b57cec5SDimitry Andric   else
1310b57cec5SDimitry Andric     m_strings.push_back(str);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
InsertStringAtIndex(size_t idx,std::string && str)1340b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, std::string &&str) {
1350b57cec5SDimitry Andric   if (idx < m_strings.size())
1360b57cec5SDimitry Andric     m_strings.insert(m_strings.begin() + idx, str);
1370b57cec5SDimitry Andric   else
1380b57cec5SDimitry Andric     m_strings.push_back(str);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
DeleteStringAtIndex(size_t idx)1410b57cec5SDimitry Andric void StringList::DeleteStringAtIndex(size_t idx) {
1420b57cec5SDimitry Andric   if (idx < m_strings.size())
1430b57cec5SDimitry Andric     m_strings.erase(m_strings.begin() + idx);
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
SplitIntoLines(const std::string & lines)1460b57cec5SDimitry Andric size_t StringList::SplitIntoLines(const std::string &lines) {
1470b57cec5SDimitry Andric   return SplitIntoLines(lines.c_str(), lines.size());
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
SplitIntoLines(const char * lines,size_t len)1500b57cec5SDimitry Andric size_t StringList::SplitIntoLines(const char *lines, size_t len) {
1510b57cec5SDimitry Andric   const size_t orig_size = m_strings.size();
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   if (len == 0)
1540b57cec5SDimitry Andric     return 0;
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   const char *k_newline_chars = "\r\n";
1570b57cec5SDimitry Andric   const char *p = lines;
1580b57cec5SDimitry Andric   const char *end = lines + len;
1590b57cec5SDimitry Andric   while (p < end) {
1600b57cec5SDimitry Andric     size_t count = strcspn(p, k_newline_chars);
1610b57cec5SDimitry Andric     if (count == 0) {
1620b57cec5SDimitry Andric       if (p[count] == '\r' || p[count] == '\n')
1630b57cec5SDimitry Andric         m_strings.push_back(std::string());
1640b57cec5SDimitry Andric       else
1650b57cec5SDimitry Andric         break;
1660b57cec5SDimitry Andric     } else {
1670b57cec5SDimitry Andric       if (p + count > end)
1680b57cec5SDimitry Andric         count = end - p;
1690b57cec5SDimitry Andric       m_strings.push_back(std::string(p, count));
1700b57cec5SDimitry Andric     }
1710b57cec5SDimitry Andric     if (p[count] == '\r' && p[count + 1] == '\n')
1720b57cec5SDimitry Andric       count++; // Skip an extra newline char for the DOS newline
1730b57cec5SDimitry Andric     count++;   // Skip the newline character
1740b57cec5SDimitry Andric     p += count;
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric   return m_strings.size() - orig_size;
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
RemoveBlankLines()1790b57cec5SDimitry Andric void StringList::RemoveBlankLines() {
1800b57cec5SDimitry Andric   if (GetSize() == 0)
1810b57cec5SDimitry Andric     return;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   size_t idx = 0;
1840b57cec5SDimitry Andric   while (idx < m_strings.size()) {
1850b57cec5SDimitry Andric     if (m_strings[idx].empty())
1860b57cec5SDimitry Andric       DeleteStringAtIndex(idx);
1870b57cec5SDimitry Andric     else
1880b57cec5SDimitry Andric       idx++;
1890b57cec5SDimitry Andric   }
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
CopyList(const char * item_preamble,const char * items_sep) const1920b57cec5SDimitry Andric std::string StringList::CopyList(const char *item_preamble,
1930b57cec5SDimitry Andric                                  const char *items_sep) const {
1940b57cec5SDimitry Andric   StreamString strm;
1950b57cec5SDimitry Andric   for (size_t i = 0; i < GetSize(); i++) {
1960b57cec5SDimitry Andric     if (i && items_sep && items_sep[0])
1970b57cec5SDimitry Andric       strm << items_sep;
1980b57cec5SDimitry Andric     if (item_preamble)
1990b57cec5SDimitry Andric       strm << item_preamble;
2000b57cec5SDimitry Andric     strm << GetStringAtIndex(i);
2010b57cec5SDimitry Andric   }
2025ffd83dbSDimitry Andric   return std::string(strm.GetString());
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
operator <<(const char * str)2050b57cec5SDimitry Andric StringList &StringList::operator<<(const char *str) {
2060b57cec5SDimitry Andric   AppendString(str);
2070b57cec5SDimitry Andric   return *this;
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
operator <<(const std::string & str)2100b57cec5SDimitry Andric StringList &StringList::operator<<(const std::string &str) {
2110b57cec5SDimitry Andric   AppendString(str);
2120b57cec5SDimitry Andric   return *this;
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
operator <<(const StringList & strings)215af732203SDimitry Andric StringList &StringList::operator<<(const StringList &strings) {
2160b57cec5SDimitry Andric   AppendList(strings);
2170b57cec5SDimitry Andric   return *this;
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric 
operator =(const std::vector<std::string> & rhs)2200b57cec5SDimitry Andric StringList &StringList::operator=(const std::vector<std::string> &rhs) {
2210b57cec5SDimitry Andric   m_strings.assign(rhs.begin(), rhs.end());
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   return *this;
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
LogDump(Log * log,const char * name)2260b57cec5SDimitry Andric void StringList::LogDump(Log *log, const char *name) {
2270b57cec5SDimitry Andric   if (!log)
2280b57cec5SDimitry Andric     return;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   StreamString strm;
2310b57cec5SDimitry Andric   if (name)
2320b57cec5SDimitry Andric     strm.Printf("Begin %s:\n", name);
2330b57cec5SDimitry Andric   for (const auto &s : m_strings) {
2340b57cec5SDimitry Andric     strm.Indent();
2350b57cec5SDimitry Andric     strm.Printf("%s\n", s.c_str());
2360b57cec5SDimitry Andric   }
2370b57cec5SDimitry Andric   if (name)
2380b57cec5SDimitry Andric     strm.Printf("End %s.\n", name);
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   LLDB_LOGV(log, "{0}", strm.GetData());
2410b57cec5SDimitry Andric }
242