cmStringAlgorithms.cxx 6.2 KB

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