1//===-- StringList.cpp ------------------------------------------*- C++ -*-===//
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 <stdint.h>
18#include <string.h>
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() {}
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) { m_strings.push_back(s); }
46
47void StringList::AppendString(const char *str, size_t str_len) {
48  if (str)
49    m_strings.push_back(std::string(str, str_len));
50}
51
52void StringList::AppendString(llvm::StringRef str) {
53  m_strings.push_back(str.str());
54}
55
56void StringList::AppendList(const char **strv, int strc) {
57  for (int i = 0; i < strc; ++i) {
58    if (strv[i])
59      m_strings.push_back(strv[i]);
60  }
61}
62
63void StringList::AppendList(StringList strings) {
64  m_strings.reserve(m_strings.size() + strings.GetSize());
65  m_strings.insert(m_strings.end(), strings.begin(), strings.end());
66}
67
68size_t StringList::GetSize() const { return m_strings.size(); }
69
70size_t StringList::GetMaxStringLength() const {
71  size_t max_length = 0;
72  for (const auto &s : m_strings) {
73    const size_t len = s.size();
74    if (max_length < len)
75      max_length = len;
76  }
77  return max_length;
78}
79
80const char *StringList::GetStringAtIndex(size_t idx) const {
81  if (idx < m_strings.size())
82    return m_strings[idx].c_str();
83  return nullptr;
84}
85
86void StringList::Join(const char *separator, Stream &strm) {
87  size_t size = GetSize();
88
89  if (size == 0)
90    return;
91
92  for (uint32_t i = 0; i < size; ++i) {
93    if (i > 0)
94      strm.PutCString(separator);
95    strm.PutCString(GetStringAtIndex(i));
96  }
97}
98
99void StringList::Clear() { m_strings.clear(); }
100
101std::string StringList::LongestCommonPrefix() {
102  if (m_strings.empty())
103    return {};
104
105  auto args = llvm::makeArrayRef(m_strings);
106  llvm::StringRef prefix = args.front();
107  for (auto arg : args.drop_front()) {
108    size_t count = 0;
109    for (count = 0; count < std::min(prefix.size(), arg.size()); ++count) {
110      if (prefix[count] != arg[count])
111        break;
112    }
113    prefix = prefix.take_front(count);
114  }
115  return prefix.str();
116}
117
118void StringList::InsertStringAtIndex(size_t idx, const char *str) {
119  if (str) {
120    if (idx < m_strings.size())
121      m_strings.insert(m_strings.begin() + idx, str);
122    else
123      m_strings.push_back(str);
124  }
125}
126
127void StringList::InsertStringAtIndex(size_t idx, const std::string &str) {
128  if (idx < m_strings.size())
129    m_strings.insert(m_strings.begin() + idx, str);
130  else
131    m_strings.push_back(str);
132}
133
134void StringList::InsertStringAtIndex(size_t idx, std::string &&str) {
135  if (idx < m_strings.size())
136    m_strings.insert(m_strings.begin() + idx, str);
137  else
138    m_strings.push_back(str);
139}
140
141void StringList::DeleteStringAtIndex(size_t idx) {
142  if (idx < m_strings.size())
143    m_strings.erase(m_strings.begin() + idx);
144}
145
146size_t StringList::SplitIntoLines(const std::string &lines) {
147  return SplitIntoLines(lines.c_str(), lines.size());
148}
149
150size_t StringList::SplitIntoLines(const char *lines, size_t len) {
151  const size_t orig_size = m_strings.size();
152
153  if (len == 0)
154    return 0;
155
156  const char *k_newline_chars = "\r\n";
157  const char *p = lines;
158  const char *end = lines + len;
159  while (p < end) {
160    size_t count = strcspn(p, k_newline_chars);
161    if (count == 0) {
162      if (p[count] == '\r' || p[count] == '\n')
163        m_strings.push_back(std::string());
164      else
165        break;
166    } else {
167      if (p + count > end)
168        count = end - p;
169      m_strings.push_back(std::string(p, count));
170    }
171    if (p[count] == '\r' && p[count + 1] == '\n')
172      count++; // Skip an extra newline char for the DOS newline
173    count++;   // Skip the newline character
174    p += count;
175  }
176  return m_strings.size() - orig_size;
177}
178
179void StringList::RemoveBlankLines() {
180  if (GetSize() == 0)
181    return;
182
183  size_t idx = 0;
184  while (idx < m_strings.size()) {
185    if (m_strings[idx].empty())
186      DeleteStringAtIndex(idx);
187    else
188      idx++;
189  }
190}
191
192std::string StringList::CopyList(const char *item_preamble,
193                                 const char *items_sep) const {
194  StreamString strm;
195  for (size_t i = 0; i < GetSize(); i++) {
196    if (i && items_sep && items_sep[0])
197      strm << items_sep;
198    if (item_preamble)
199      strm << item_preamble;
200    strm << GetStringAtIndex(i);
201  }
202  return strm.GetString();
203}
204
205StringList &StringList::operator<<(const char *str) {
206  AppendString(str);
207  return *this;
208}
209
210StringList &StringList::operator<<(const std::string &str) {
211  AppendString(str);
212  return *this;
213}
214
215StringList &StringList::operator<<(StringList strings) {
216  AppendList(strings);
217  return *this;
218}
219
220StringList &StringList::operator=(const std::vector<std::string> &rhs) {
221  m_strings.assign(rhs.begin(), rhs.end());
222
223  return *this;
224}
225
226void StringList::LogDump(Log *log, const char *name) {
227  if (!log)
228    return;
229
230  StreamString strm;
231  if (name)
232    strm.Printf("Begin %s:\n", name);
233  for (const auto &s : m_strings) {
234    strm.Indent();
235    strm.Printf("%s\n", s.c_str());
236  }
237  if (name)
238    strm.Printf("End %s.\n", name);
239
240  LLDB_LOGV(log, "{0}", strm.GetData());
241}
242