1*0b57cec5SDimitry Andric //===-- StringList.cpp ----------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "lldb/Utility/StringList.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
12*0b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
13*0b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric #include <algorithm>
17*0b57cec5SDimitry Andric #include <cstdint>
18*0b57cec5SDimitry Andric #include <cstring>
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric using namespace lldb_private;
21*0b57cec5SDimitry Andric 
StringList()22*0b57cec5SDimitry Andric StringList::StringList() : m_strings() {}
23*0b57cec5SDimitry Andric 
StringList(const char * str)24*0b57cec5SDimitry Andric StringList::StringList(const char *str) : m_strings() {
25*0b57cec5SDimitry Andric   if (str)
26*0b57cec5SDimitry Andric     m_strings.push_back(str);
27*0b57cec5SDimitry Andric }
28*0b57cec5SDimitry Andric 
StringList(const char ** strv,int strc)29*0b57cec5SDimitry Andric StringList::StringList(const char **strv, int strc) : m_strings() {
30*0b57cec5SDimitry Andric   for (int i = 0; i < strc; ++i) {
31*0b57cec5SDimitry Andric     if (strv[i])
32*0b57cec5SDimitry Andric       m_strings.push_back(strv[i]);
33*0b57cec5SDimitry Andric   }
34*0b57cec5SDimitry Andric }
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric StringList::~StringList() = default;
37*0b57cec5SDimitry Andric 
AppendString(const char * str)38*0b57cec5SDimitry Andric void StringList::AppendString(const char *str) {
39*0b57cec5SDimitry Andric   if (str)
40*0b57cec5SDimitry Andric     m_strings.push_back(str);
41*0b57cec5SDimitry Andric }
42*0b57cec5SDimitry Andric 
AppendString(const std::string & s)43*0b57cec5SDimitry Andric void StringList::AppendString(const std::string &s) { m_strings.push_back(s); }
44*0b57cec5SDimitry Andric 
AppendString(std::string && s)45*0b57cec5SDimitry Andric void StringList::AppendString(std::string &&s) {
46*0b57cec5SDimitry Andric   m_strings.push_back(std::move(s));
47*0b57cec5SDimitry Andric }
48*0b57cec5SDimitry Andric 
AppendString(const char * str,size_t str_len)49*0b57cec5SDimitry Andric void StringList::AppendString(const char *str, size_t str_len) {
50*0b57cec5SDimitry Andric   if (str)
51*0b57cec5SDimitry Andric     m_strings.push_back(std::string(str, str_len));
52*0b57cec5SDimitry Andric }
53*0b57cec5SDimitry Andric 
AppendString(llvm::StringRef str)54*0b57cec5SDimitry Andric void StringList::AppendString(llvm::StringRef str) {
55*0b57cec5SDimitry Andric   m_strings.push_back(str.str());
56*0b57cec5SDimitry Andric }
57*0b57cec5SDimitry Andric 
AppendString(const llvm::Twine & str)58*0b57cec5SDimitry Andric void StringList::AppendString(const llvm::Twine &str) {
59*0b57cec5SDimitry Andric   m_strings.push_back(str.str());
60*0b57cec5SDimitry Andric }
61*0b57cec5SDimitry Andric 
AppendList(const char ** strv,int strc)62*0b57cec5SDimitry Andric void StringList::AppendList(const char **strv, int strc) {
63*0b57cec5SDimitry Andric   for (int i = 0; i < strc; ++i) {
64*0b57cec5SDimitry Andric     if (strv[i])
65*0b57cec5SDimitry Andric       m_strings.push_back(strv[i]);
66*0b57cec5SDimitry Andric   }
67*0b57cec5SDimitry Andric }
68*0b57cec5SDimitry Andric 
AppendList(StringList strings)69*0b57cec5SDimitry Andric void StringList::AppendList(StringList strings) {
70*0b57cec5SDimitry Andric   m_strings.reserve(m_strings.size() + strings.GetSize());
71*0b57cec5SDimitry Andric   m_strings.insert(m_strings.end(), strings.begin(), strings.end());
72*0b57cec5SDimitry Andric }
73*0b57cec5SDimitry Andric 
GetSize() const74*0b57cec5SDimitry Andric size_t StringList::GetSize() const { return m_strings.size(); }
75*0b57cec5SDimitry Andric 
GetMaxStringLength() const76*0b57cec5SDimitry Andric size_t StringList::GetMaxStringLength() const {
77*0b57cec5SDimitry Andric   size_t max_length = 0;
78*0b57cec5SDimitry Andric   for (const auto &s : m_strings) {
79*0b57cec5SDimitry Andric     const size_t len = s.size();
80*0b57cec5SDimitry Andric     if (max_length < len)
81*0b57cec5SDimitry Andric       max_length = len;
82*0b57cec5SDimitry Andric   }
83*0b57cec5SDimitry Andric   return max_length;
84*0b57cec5SDimitry Andric }
85*0b57cec5SDimitry Andric 
GetStringAtIndex(size_t idx) const86*0b57cec5SDimitry Andric const char *StringList::GetStringAtIndex(size_t idx) const {
87*0b57cec5SDimitry Andric   if (idx < m_strings.size())
88*0b57cec5SDimitry Andric     return m_strings[idx].c_str();
89*0b57cec5SDimitry Andric   return nullptr;
90*0b57cec5SDimitry Andric }
91*0b57cec5SDimitry Andric 
Join(const char * separator,Stream & strm)92*0b57cec5SDimitry Andric void StringList::Join(const char *separator, Stream &strm) {
93*0b57cec5SDimitry Andric   size_t size = GetSize();
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric   if (size == 0)
96*0b57cec5SDimitry Andric     return;
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric   for (uint32_t i = 0; i < size; ++i) {
99*0b57cec5SDimitry Andric     if (i > 0)
100*0b57cec5SDimitry Andric       strm.PutCString(separator);
101*0b57cec5SDimitry Andric     strm.PutCString(GetStringAtIndex(i));
102*0b57cec5SDimitry Andric   }
103*0b57cec5SDimitry Andric }
104*0b57cec5SDimitry Andric 
Clear()105*0b57cec5SDimitry Andric void StringList::Clear() { m_strings.clear(); }
106*0b57cec5SDimitry Andric 
LongestCommonPrefix()107*0b57cec5SDimitry Andric std::string StringList::LongestCommonPrefix() {
108*0b57cec5SDimitry Andric   if (m_strings.empty())
109*0b57cec5SDimitry Andric     return {};
110*0b57cec5SDimitry Andric 
111*0b57cec5SDimitry Andric   auto args = llvm::ArrayRef(m_strings);
112*0b57cec5SDimitry Andric   llvm::StringRef prefix = args.front();
113*0b57cec5SDimitry Andric   for (auto arg : args.drop_front()) {
114*0b57cec5SDimitry Andric     size_t count = 0;
115*0b57cec5SDimitry Andric     for (count = 0; count < std::min(prefix.size(), arg.size()); ++count) {
116*0b57cec5SDimitry Andric       if (prefix[count] != arg[count])
117*0b57cec5SDimitry Andric         break;
118*0b57cec5SDimitry Andric     }
119*0b57cec5SDimitry Andric     prefix = prefix.take_front(count);
120*0b57cec5SDimitry Andric   }
121*0b57cec5SDimitry Andric   return prefix.str();
122*0b57cec5SDimitry Andric }
123*0b57cec5SDimitry Andric 
InsertStringAtIndex(size_t idx,const char * str)124*0b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, const char *str) {
125*0b57cec5SDimitry Andric   if (str) {
126*0b57cec5SDimitry Andric     if (idx < m_strings.size())
127*0b57cec5SDimitry Andric       m_strings.insert(m_strings.begin() + idx, str);
128*0b57cec5SDimitry Andric     else
129*0b57cec5SDimitry Andric       m_strings.push_back(str);
130*0b57cec5SDimitry Andric   }
131*0b57cec5SDimitry Andric }
132*0b57cec5SDimitry Andric 
InsertStringAtIndex(size_t idx,const std::string & str)133*0b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, const std::string &str) {
134*0b57cec5SDimitry Andric   if (idx < m_strings.size())
135*0b57cec5SDimitry Andric     m_strings.insert(m_strings.begin() + idx, str);
136*0b57cec5SDimitry Andric   else
137*0b57cec5SDimitry Andric     m_strings.push_back(str);
138*0b57cec5SDimitry Andric }
139*0b57cec5SDimitry Andric 
InsertStringAtIndex(size_t idx,std::string && str)140*0b57cec5SDimitry Andric void StringList::InsertStringAtIndex(size_t idx, std::string &&str) {
141*0b57cec5SDimitry Andric   if (idx < m_strings.size())
142*0b57cec5SDimitry Andric     m_strings.insert(m_strings.begin() + idx, std::move(str));
143*0b57cec5SDimitry Andric   else
144*0b57cec5SDimitry Andric     m_strings.push_back(std::move(str));
145*0b57cec5SDimitry Andric }
146*0b57cec5SDimitry Andric 
DeleteStringAtIndex(size_t idx)147*0b57cec5SDimitry Andric void StringList::DeleteStringAtIndex(size_t idx) {
148*0b57cec5SDimitry Andric   if (idx < m_strings.size())
149*0b57cec5SDimitry Andric     m_strings.erase(m_strings.begin() + idx);
150*0b57cec5SDimitry Andric }
151*0b57cec5SDimitry Andric 
SplitIntoLines(const std::string & lines)152*0b57cec5SDimitry Andric size_t StringList::SplitIntoLines(const std::string &lines) {
153*0b57cec5SDimitry Andric   return SplitIntoLines(lines.c_str(), lines.size());
154*0b57cec5SDimitry Andric }
155*0b57cec5SDimitry Andric 
SplitIntoLines(const char * lines,size_t len)156*0b57cec5SDimitry Andric size_t StringList::SplitIntoLines(const char *lines, size_t len) {
157*0b57cec5SDimitry Andric   const size_t orig_size = m_strings.size();
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric   if (len == 0)
160*0b57cec5SDimitry Andric     return 0;
161*0b57cec5SDimitry Andric 
162*0b57cec5SDimitry Andric   const char *k_newline_chars = "\r\n";
163*0b57cec5SDimitry Andric   const char *p = lines;
164*0b57cec5SDimitry Andric   const char *end = lines + len;
165*0b57cec5SDimitry Andric   while (p < end) {
166*0b57cec5SDimitry Andric     size_t count = strcspn(p, k_newline_chars);
167*0b57cec5SDimitry Andric     if (count == 0) {
168*0b57cec5SDimitry Andric       if (p[count] == '\r' || p[count] == '\n')
169*0b57cec5SDimitry Andric         m_strings.push_back(std::string());
170*0b57cec5SDimitry Andric       else
171*0b57cec5SDimitry Andric         break;
172*0b57cec5SDimitry Andric     } else {
173*0b57cec5SDimitry Andric       if (p + count > end)
174*0b57cec5SDimitry Andric         count = end - p;
175*0b57cec5SDimitry Andric       m_strings.push_back(std::string(p, count));
176*0b57cec5SDimitry Andric     }
177*0b57cec5SDimitry Andric     if (p[count] == '\r' && p[count + 1] == '\n')
178*0b57cec5SDimitry Andric       count++; // Skip an extra newline char for the DOS newline
179*0b57cec5SDimitry Andric     count++;   // Skip the newline character
180*0b57cec5SDimitry Andric     p += count;
181*0b57cec5SDimitry Andric   }
182*0b57cec5SDimitry Andric   return m_strings.size() - orig_size;
183*0b57cec5SDimitry Andric }
184*0b57cec5SDimitry Andric 
RemoveBlankLines()185*0b57cec5SDimitry Andric void StringList::RemoveBlankLines() {
186*0b57cec5SDimitry Andric   if (GetSize() == 0)
187*0b57cec5SDimitry Andric     return;
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric   size_t idx = 0;
190*0b57cec5SDimitry Andric   while (idx < m_strings.size()) {
191*0b57cec5SDimitry Andric     if (m_strings[idx].empty())
192*0b57cec5SDimitry Andric       DeleteStringAtIndex(idx);
193*0b57cec5SDimitry Andric     else
194*0b57cec5SDimitry Andric       idx++;
195*0b57cec5SDimitry Andric   }
196*0b57cec5SDimitry Andric }
197*0b57cec5SDimitry Andric 
CopyList(const char * item_preamble,const char * items_sep) const198*0b57cec5SDimitry Andric std::string StringList::CopyList(const char *item_preamble,
199*0b57cec5SDimitry Andric                                  const char *items_sep) const {
200*0b57cec5SDimitry Andric   StreamString strm;
201*0b57cec5SDimitry Andric   for (size_t i = 0; i < GetSize(); i++) {
202*0b57cec5SDimitry Andric     if (i && items_sep && items_sep[0])
203*0b57cec5SDimitry Andric       strm << items_sep;
204*0b57cec5SDimitry Andric     if (item_preamble)
205*0b57cec5SDimitry Andric       strm << item_preamble;
206*0b57cec5SDimitry Andric     strm << GetStringAtIndex(i);
207*0b57cec5SDimitry Andric   }
208*0b57cec5SDimitry Andric   return std::string(strm.GetString());
209*0b57cec5SDimitry Andric }
210*0b57cec5SDimitry Andric 
operator <<(const char * str)211*0b57cec5SDimitry Andric StringList &StringList::operator<<(const char *str) {
212*0b57cec5SDimitry Andric   AppendString(str);
213*0b57cec5SDimitry Andric   return *this;
214*0b57cec5SDimitry Andric }
215*0b57cec5SDimitry Andric 
operator <<(const std::string & str)216*0b57cec5SDimitry Andric StringList &StringList::operator<<(const std::string &str) {
217*0b57cec5SDimitry Andric   AppendString(str);
218*0b57cec5SDimitry Andric   return *this;
219*0b57cec5SDimitry Andric }
220*0b57cec5SDimitry Andric 
operator <<(const StringList & strings)221*0b57cec5SDimitry Andric StringList &StringList::operator<<(const StringList &strings) {
222*0b57cec5SDimitry Andric   AppendList(strings);
223*0b57cec5SDimitry Andric   return *this;
224*0b57cec5SDimitry Andric }
225*0b57cec5SDimitry Andric 
operator =(const std::vector<std::string> & rhs)226*0b57cec5SDimitry Andric StringList &StringList::operator=(const std::vector<std::string> &rhs) {
227*0b57cec5SDimitry Andric   m_strings.assign(rhs.begin(), rhs.end());
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric   return *this;
230*0b57cec5SDimitry Andric }
231*0b57cec5SDimitry Andric 
LogDump(Log * log,const char * name)232*0b57cec5SDimitry Andric void StringList::LogDump(Log *log, const char *name) {
233*0b57cec5SDimitry Andric   if (!log)
234*0b57cec5SDimitry Andric     return;
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric   StreamString strm;
237*0b57cec5SDimitry Andric   if (name)
238*0b57cec5SDimitry Andric     strm.Printf("Begin %s:\n", name);
239*0b57cec5SDimitry Andric   for (const auto &s : m_strings) {
240*0b57cec5SDimitry Andric     strm.Indent();
241*0b57cec5SDimitry Andric     strm.Printf("%s\n", s.c_str());
242*0b57cec5SDimitry Andric   }
243*0b57cec5SDimitry Andric   if (name)
244*0b57cec5SDimitry Andric     strm.Printf("End %s.\n", name);
245*0b57cec5SDimitry Andric 
246*0b57cec5SDimitry Andric   LLDB_LOGV(log, "{0}", strm.GetData());
247*0b57cec5SDimitry Andric }
248*0b57cec5SDimitry Andric