cmStringAlgorithms.cxx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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"
  4. #include <algorithm>
  5. #include <cerrno>
  6. #include <cstddef> // IWYU pragma: keep
  7. #include <cstdio>
  8. #include <cstdlib>
  9. #include <iterator>
  10. std::string cmTrimWhitespace(cm::string_view str)
  11. {
  12. // XXX(clang-tidy): This declaration and the next cannot be `const auto*`
  13. // because the qualification of `auto` is platform-dependent.
  14. // NOLINTNEXTLINE(readability-qualified-auto)
  15. auto start = str.begin();
  16. while (start != str.end() && cmIsSpace(*start)) {
  17. ++start;
  18. }
  19. if (start == str.end()) {
  20. return std::string();
  21. }
  22. // NOLINTNEXTLINE(readability-qualified-auto)
  23. auto stop = str.end() - 1;
  24. while (cmIsSpace(*stop)) {
  25. --stop;
  26. }
  27. return std::string(start, stop + 1);
  28. }
  29. std::string cmRemoveQuotes(cm::string_view str)
  30. {
  31. // We process only strings that have two quotes at least.
  32. // Also front() and back() are only defined behavior on non empty strings.
  33. if (str.size() >= 2 && //
  34. str.front() == '"' && //
  35. str.back() == '"') {
  36. // Remove a quote from the front and back
  37. str.remove_prefix(1);
  38. str.remove_suffix(1);
  39. }
  40. return std::string(str);
  41. }
  42. std::string cmEscapeQuotes(cm::string_view str)
  43. {
  44. std::string result;
  45. result.reserve(str.size());
  46. for (const char ch : str) {
  47. if (ch == '"') {
  48. result += '\\';
  49. }
  50. result += ch;
  51. }
  52. return result;
  53. }
  54. std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep)
  55. {
  56. std::vector<std::string> tokens;
  57. cm::string_view::size_type tokend = 0;
  58. do {
  59. cm::string_view::size_type tokstart = str.find_first_not_of(sep, tokend);
  60. if (tokstart == cm::string_view::npos) {
  61. break; // no more tokens
  62. }
  63. tokend = str.find_first_of(sep, tokstart);
  64. if (tokend == cm::string_view::npos) {
  65. tokens.emplace_back(str.substr(tokstart));
  66. } else {
  67. tokens.emplace_back(str.substr(tokstart, tokend - tokstart));
  68. }
  69. } while (tokend != cm::string_view::npos);
  70. if (tokens.empty()) {
  71. tokens.emplace_back();
  72. }
  73. return tokens;
  74. }
  75. namespace {
  76. template <std::size_t N, typename T>
  77. inline void MakeDigits(cm::string_view& view, char (&digits)[N],
  78. const char* pattern, T value)
  79. {
  80. int res = std::snprintf(digits, N, pattern, value);
  81. if (res > 0 && res < static_cast<int>(N)) {
  82. view = cm::string_view(digits, static_cast<std::size_t>(res));
  83. }
  84. }
  85. } // unnamed namespace
  86. cmAlphaNum::cmAlphaNum(int val)
  87. {
  88. MakeDigits(this->View_, this->Digits_, "%i", val);
  89. }
  90. cmAlphaNum::cmAlphaNum(unsigned int val)
  91. {
  92. MakeDigits(this->View_, this->Digits_, "%u", val);
  93. }
  94. cmAlphaNum::cmAlphaNum(long int val)
  95. {
  96. MakeDigits(this->View_, this->Digits_, "%li", val);
  97. }
  98. cmAlphaNum::cmAlphaNum(unsigned long int val)
  99. {
  100. MakeDigits(this->View_, this->Digits_, "%lu", val);
  101. }
  102. cmAlphaNum::cmAlphaNum(long long int val)
  103. {
  104. MakeDigits(this->View_, this->Digits_, "%lli", val);
  105. }
  106. cmAlphaNum::cmAlphaNum(unsigned long long int val)
  107. {
  108. MakeDigits(this->View_, this->Digits_, "%llu", val);
  109. }
  110. cmAlphaNum::cmAlphaNum(float val)
  111. {
  112. MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val));
  113. }
  114. cmAlphaNum::cmAlphaNum(double val)
  115. {
  116. MakeDigits(this->View_, this->Digits_, "%g", val);
  117. }
  118. std::string cmCatViews(
  119. std::initializer_list<std::pair<cm::string_view, std::string*>> views)
  120. {
  121. std::size_t totalSize = 0;
  122. std::string* rvalueString = nullptr;
  123. std::size_t rvalueStringLength = 0;
  124. std::size_t rvalueStringOffset = 0;
  125. for (auto const& view : views) {
  126. // Find the rvalue string with the largest capacity.
  127. if (view.second &&
  128. (!rvalueString ||
  129. view.second->capacity() > rvalueString->capacity())) {
  130. rvalueString = view.second;
  131. rvalueStringLength = rvalueString->length();
  132. rvalueStringOffset = totalSize;
  133. }
  134. totalSize += view.first.size();
  135. }
  136. std::string result;
  137. std::string::size_type initialLen = 0;
  138. if (rvalueString && rvalueString->capacity() >= totalSize) {
  139. result = std::move(*rvalueString);
  140. } else {
  141. rvalueString = nullptr;
  142. }
  143. result.resize(totalSize);
  144. if (rvalueString && rvalueStringOffset > 0) {
  145. std::copy_backward(result.begin(), result.begin() + rvalueStringLength,
  146. result.begin() + rvalueStringOffset +
  147. rvalueStringLength);
  148. }
  149. std::string::iterator sit = result.begin() + initialLen;
  150. for (auto const& view : views) {
  151. if (rvalueString && view.second == rvalueString) {
  152. sit += rvalueStringLength;
  153. } else {
  154. sit = std::copy_n(view.first.data(), view.first.size(), sit);
  155. }
  156. }
  157. return result;
  158. }
  159. bool cmStrToLong(const char* str, long* value)
  160. {
  161. errno = 0;
  162. char* endp;
  163. *value = strtol(str, &endp, 10);
  164. return (*endp == '\0') && (endp != str) && (errno == 0);
  165. }
  166. bool cmStrToLong(std::string const& str, long* value)
  167. {
  168. return cmStrToLong(str.c_str(), value);
  169. }
  170. bool cmStrToULong(const char* str, unsigned long* value)
  171. {
  172. errno = 0;
  173. char* endp;
  174. while (cmIsSpace(*str)) {
  175. ++str;
  176. }
  177. if (*str == '-') {
  178. return false;
  179. }
  180. *value = strtoul(str, &endp, 10);
  181. return (*endp == '\0') && (endp != str) && (errno == 0);
  182. }
  183. bool cmStrToULong(std::string const& str, unsigned long* value)
  184. {
  185. return cmStrToULong(str.c_str(), value);
  186. }
  187. bool cmStrToLongLong(const char* str, long long* value)
  188. {
  189. errno = 0;
  190. char* endp;
  191. *value = strtoll(str, &endp, 10);
  192. return (*endp == '\0') && (endp != str) && (errno == 0);
  193. }
  194. bool cmStrToLongLong(std::string const& str, long long* value)
  195. {
  196. return cmStrToLongLong(str.c_str(), value);
  197. }
  198. bool cmStrToULongLong(const char* str, unsigned long long* value)
  199. {
  200. errno = 0;
  201. char* endp;
  202. while (cmIsSpace(*str)) {
  203. ++str;
  204. }
  205. if (*str == '-') {
  206. return false;
  207. }
  208. *value = strtoull(str, &endp, 10);
  209. return (*endp == '\0') && (endp != str) && (errno == 0);
  210. }
  211. bool cmStrToULongLong(std::string const& str, unsigned long long* value)
  212. {
  213. return cmStrToULongLong(str.c_str(), value);
  214. }
  215. template <typename Range>
  216. std::size_t getJoinedLength(Range const& rng, cm::string_view separator)
  217. {
  218. std::size_t rangeLength{};
  219. for (auto const& item : rng) {
  220. rangeLength += item.size();
  221. }
  222. auto const separatorsLength = (rng.size() - 1) * separator.size();
  223. return rangeLength + separatorsLength;
  224. }
  225. template <typename Range>
  226. std::string cmJoinImpl(Range const& rng, cm::string_view separator,
  227. cm::string_view initial)
  228. {
  229. if (rng.empty()) {
  230. return { std::begin(initial), std::end(initial) };
  231. }
  232. std::string result;
  233. result.reserve(initial.size() + getJoinedLength(rng, separator));
  234. result.append(std::begin(initial), std::end(initial));
  235. auto begin = std::begin(rng);
  236. auto end = std::end(rng);
  237. result += *begin;
  238. for (++begin; begin != end; ++begin) {
  239. result.append(std::begin(separator), std::end(separator));
  240. result += *begin;
  241. }
  242. return result;
  243. }
  244. std::string cmJoin(std::vector<std::string> const& rng,
  245. cm::string_view separator, cm::string_view initial)
  246. {
  247. return cmJoinImpl(rng, separator, initial);
  248. }
  249. std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
  250. cm::string_view initial)
  251. {
  252. return cmJoinImpl(rng, separator, initial);
  253. }