1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmStringAlgorithms.h"
7 #include <cstddef> // IWYU pragma: keep
12 std::string cmTrimWhitespace(cm::string_view str)
14 // XXX(clang-tidy): This declaration and the next cannot be `const auto*`
15 // because the qualification of `auto` is platform-dependent.
16 // NOLINTNEXTLINE(readability-qualified-auto)
17 auto start = str.begin();
18 while (start != str.end() && cmIsSpace(*start)) {
21 if (start == str.end()) {
24 // NOLINTNEXTLINE(readability-qualified-auto)
25 auto stop = str.end() - 1;
26 while (cmIsSpace(*stop)) {
29 return std::string(start, stop + 1);
32 std::string cmRemoveQuotes(cm::string_view str)
34 // We process only strings that have two quotes at least.
35 // Also front() and back() are only defined behavior on non empty strings.
36 if (str.size() >= 2 && //
37 str.front() == '"' && //
39 // Remove a quote from the front and back
43 return std::string(str);
46 std::string cmEscapeQuotes(cm::string_view str)
49 result.reserve(str.size());
50 for (const char ch : str) {
59 std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep)
61 std::vector<std::string> tokens;
62 cm::string_view::size_type tokend = 0;
65 cm::string_view::size_type tokstart = str.find_first_not_of(sep, tokend);
66 if (tokstart == cm::string_view::npos) {
67 break; // no more tokens
69 tokend = str.find_first_of(sep, tokstart);
70 if (tokend == cm::string_view::npos) {
71 tokens.emplace_back(str.substr(tokstart));
73 tokens.emplace_back(str.substr(tokstart, tokend - tokstart));
75 } while (tokend != cm::string_view::npos);
78 tokens.emplace_back();
83 void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
86 // If argument is empty, it is an empty list.
87 if (!emptyArgs && arg.empty()) {
91 // if there are no ; in the name then just copy the current string
92 if (arg.find(';') == cm::string_view::npos) {
93 argsOut.emplace_back(arg);
98 // Break the string at non-escaped semicolons not nested in [].
99 int squareNesting = 0;
100 cm::string_view::iterator last = arg.begin();
101 cm::string_view::iterator const cend = arg.end();
102 for (cm::string_view::iterator c = last; c != cend; ++c) {
105 // We only want to allow escaping of semicolons. Other
106 // escapes should not be processed here.
107 cm::string_view::iterator cnext = c + 1;
108 if ((cnext != cend) && *cnext == ';') {
109 newArg.append(last, c);
110 // Skip over the escape character
122 // Break the string here if we are not nested inside square
124 if (squareNesting == 0) {
125 newArg.append(last, c);
126 // Skip over the semicolon
128 if (!newArg.empty() || emptyArgs) {
129 // Add the last argument if the string is not empty.
130 argsOut.push_back(newArg);
136 // Just append this character.
140 newArg.append(last, cend);
141 if (!newArg.empty() || emptyArgs) {
142 // Add the last argument if the string is not empty.
143 argsOut.push_back(std::move(newArg));
147 std::vector<std::string> cmExpandedList(cm::string_view arg, bool emptyArgs)
149 std::vector<std::string> argsOut;
150 cmExpandList(arg, argsOut, emptyArgs);
155 template <std::size_t N, typename T>
156 inline void MakeDigits(cm::string_view& view, char (&digits)[N],
157 const char* pattern, T value)
159 int res = std::snprintf(digits, N, pattern, value);
160 if (res > 0 && res < static_cast<int>(N)) {
161 view = cm::string_view(digits, static_cast<std::size_t>(res));
164 } // unnamed namespace
166 cmAlphaNum::cmAlphaNum(int val)
168 MakeDigits(this->View_, this->Digits_, "%i", val);
171 cmAlphaNum::cmAlphaNum(unsigned int val)
173 MakeDigits(this->View_, this->Digits_, "%u", val);
176 cmAlphaNum::cmAlphaNum(long int val)
178 MakeDigits(this->View_, this->Digits_, "%li", val);
181 cmAlphaNum::cmAlphaNum(unsigned long int val)
183 MakeDigits(this->View_, this->Digits_, "%lu", val);
186 cmAlphaNum::cmAlphaNum(long long int val)
188 MakeDigits(this->View_, this->Digits_, "%lli", val);
191 cmAlphaNum::cmAlphaNum(unsigned long long int val)
193 MakeDigits(this->View_, this->Digits_, "%llu", val);
196 cmAlphaNum::cmAlphaNum(float val)
198 MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val));
201 cmAlphaNum::cmAlphaNum(double val)
203 MakeDigits(this->View_, this->Digits_, "%g", val);
206 std::string cmCatViews(std::initializer_list<cm::string_view> views)
208 std::size_t total_size = 0;
209 for (cm::string_view const& view : views) {
210 total_size += view.size();
213 std::string result(total_size, '\0');
214 std::string::iterator sit = result.begin();
215 for (cm::string_view const& view : views) {
216 sit = std::copy_n(view.data(), view.size(), sit);
221 bool cmStrToLong(const char* str, long* value)
225 *value = strtol(str, &endp, 10);
226 return (*endp == '\0') && (endp != str) && (errno == 0);
229 bool cmStrToLong(std::string const& str, long* value)
231 return cmStrToLong(str.c_str(), value);
234 bool cmStrToULong(const char* str, unsigned long* value)
238 while (cmIsSpace(*str)) {
244 *value = strtoul(str, &endp, 10);
245 return (*endp == '\0') && (endp != str) && (errno == 0);
248 bool cmStrToULong(std::string const& str, unsigned long* value)
250 return cmStrToULong(str.c_str(), value);
253 bool cmStrToLongLong(const char* str, long long* value)
257 *value = strtoll(str, &endp, 10);
258 return (*endp == '\0') && (endp != str) && (errno == 0);
261 bool cmStrToLongLong(std::string const& str, long long* value)
263 return cmStrToLongLong(str.c_str(), value);
266 bool cmStrToULongLong(const char* str, unsigned long long* value)
270 while (cmIsSpace(*str)) {
276 *value = strtoull(str, &endp, 10);
277 return (*endp == '\0') && (endp != str) && (errno == 0);
280 bool cmStrToULongLong(std::string const& str, unsigned long long* value)
282 return cmStrToULongLong(str.c_str(), value);
285 template <typename Range>
286 std::size_t getJoinedLength(Range const& rng, cm::string_view separator)
288 std::size_t rangeLength{};
289 for (auto const& item : rng) {
290 rangeLength += item.size();
293 auto const separatorsLength = (rng.size() - 1) * separator.size();
295 return rangeLength + separatorsLength;
298 template <typename Range>
299 std::string cmJoinImpl(Range const& rng, cm::string_view separator,
300 cm::string_view initial)
303 return { std::begin(initial), std::end(initial) };
307 result.reserve(initial.size() + getJoinedLength(rng, separator));
308 result.append(std::begin(initial), std::end(initial));
310 auto begin = std::begin(rng);
311 auto end = std::end(rng);
314 for (++begin; begin != end; ++begin) {
315 result.append(std::begin(separator), std::end(separator));
322 std::string cmJoin(std::vector<std::string> const& rng,
323 cm::string_view separator, cm::string_view initial)
325 return cmJoinImpl(rng, separator, initial);
328 std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
329 cm::string_view initial)
331 return cmJoinImpl(rng, separator, initial);