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