cmStringAlgorithms.cxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. 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. std::string cmRemoveQuotes(cm::string_view str)
  37. {
  38. // We process only strings that have two quotes at least.
  39. // Also front() and back() are only defined behavior on non empty strings.
  40. if (str.size() >= 2 && //
  41. str.front() == '"' && //
  42. str.back() == '"') {
  43. // Remove a quote from the front and back
  44. str.remove_prefix(1);
  45. str.remove_suffix(1);
  46. }
  47. return std::string(str);
  48. }
  49. std::string cmEscapeQuotes(cm::string_view str)
  50. {
  51. std::string result;
  52. result.reserve(str.size());
  53. for (const char ch : str) {
  54. if (ch == '"') {
  55. result += '\\';
  56. }
  57. result += ch;
  58. }
  59. return result;
  60. }
  61. namespace {
  62. template <std::size_t N, typename T>
  63. inline void MakeDigits(cm::string_view& view, char (&digits)[N],
  64. const char* pattern, T value)
  65. {
  66. int res = std::snprintf(digits, N, pattern, value);
  67. if (res > 0 && res < static_cast<int>(N)) {
  68. view = cm::string_view(digits, static_cast<std::size_t>(res));
  69. }
  70. }
  71. } // unnamed namespace
  72. cmAlphaNum::cmAlphaNum(int val)
  73. {
  74. MakeDigits(this->View_, this->Digits_, "%i", val);
  75. }
  76. cmAlphaNum::cmAlphaNum(unsigned int val)
  77. {
  78. MakeDigits(this->View_, this->Digits_, "%u", val);
  79. }
  80. cmAlphaNum::cmAlphaNum(long int val)
  81. {
  82. MakeDigits(this->View_, this->Digits_, "%li", val);
  83. }
  84. cmAlphaNum::cmAlphaNum(unsigned long int val)
  85. {
  86. MakeDigits(this->View_, this->Digits_, "%lu", val);
  87. }
  88. cmAlphaNum::cmAlphaNum(long long int val)
  89. {
  90. MakeDigits(this->View_, this->Digits_, "%lli", val);
  91. }
  92. cmAlphaNum::cmAlphaNum(unsigned long long int val)
  93. {
  94. MakeDigits(this->View_, this->Digits_, "%llu", val);
  95. }
  96. cmAlphaNum::cmAlphaNum(float val)
  97. {
  98. MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val));
  99. }
  100. cmAlphaNum::cmAlphaNum(double val)
  101. {
  102. MakeDigits(this->View_, this->Digits_, "%g", val);
  103. }
  104. std::string cmCatViews(
  105. std::initializer_list<std::pair<cm::string_view, std::string*>> views)
  106. {
  107. std::size_t totalSize = 0;
  108. std::string* rvalueString = nullptr;
  109. std::size_t rvalueStringLength = 0;
  110. std::size_t rvalueStringOffset = 0;
  111. for (auto const& view : views) {
  112. // Find the rvalue string with the largest capacity.
  113. if (view.second &&
  114. (!rvalueString ||
  115. view.second->capacity() > rvalueString->capacity())) {
  116. rvalueString = view.second;
  117. rvalueStringLength = rvalueString->length();
  118. rvalueStringOffset = totalSize;
  119. }
  120. totalSize += view.first.size();
  121. }
  122. std::string result;
  123. std::string::size_type initialLen = 0;
  124. if (rvalueString && rvalueString->capacity() >= totalSize) {
  125. result = std::move(*rvalueString);
  126. } else {
  127. rvalueString = nullptr;
  128. }
  129. result.resize(totalSize);
  130. if (rvalueString && rvalueStringOffset > 0) {
  131. std::copy_backward(result.begin(), result.begin() + rvalueStringLength,
  132. result.begin() + rvalueStringOffset +
  133. rvalueStringLength);
  134. }
  135. std::string::iterator sit = result.begin() + initialLen;
  136. for (auto const& view : views) {
  137. if (rvalueString && view.second == rvalueString) {
  138. sit += rvalueStringLength;
  139. } else {
  140. sit = std::copy_n(view.first.data(), view.first.size(), sit);
  141. }
  142. }
  143. return result;
  144. }
  145. bool cmStrToLong(const char* str, long* value)
  146. {
  147. errno = 0;
  148. char* endp;
  149. *value = strtol(str, &endp, 10);
  150. return (*endp == '\0') && (endp != str) && (errno == 0);
  151. }
  152. bool cmStrToLong(std::string const& str, long* value)
  153. {
  154. return cmStrToLong(str.c_str(), value);
  155. }
  156. bool cmStrToULong(const char* str, unsigned long* value)
  157. {
  158. errno = 0;
  159. char* endp;
  160. while (cmIsSpace(*str)) {
  161. ++str;
  162. }
  163. if (*str == '-') {
  164. return false;
  165. }
  166. *value = strtoul(str, &endp, 10);
  167. return (*endp == '\0') && (endp != str) && (errno == 0);
  168. }
  169. bool cmStrToULong(std::string const& str, unsigned long* value)
  170. {
  171. return cmStrToULong(str.c_str(), value);
  172. }
  173. bool cmStrToLongLong(const char* str, long long* value)
  174. {
  175. errno = 0;
  176. char* endp;
  177. *value = strtoll(str, &endp, 10);
  178. return (*endp == '\0') && (endp != str) && (errno == 0);
  179. }
  180. bool cmStrToLongLong(std::string const& str, long long* value)
  181. {
  182. return cmStrToLongLong(str.c_str(), value);
  183. }
  184. bool cmStrToULongLong(const char* str, unsigned long long* value)
  185. {
  186. errno = 0;
  187. char* endp;
  188. while (cmIsSpace(*str)) {
  189. ++str;
  190. }
  191. if (*str == '-') {
  192. return false;
  193. }
  194. *value = strtoull(str, &endp, 10);
  195. return (*endp == '\0') && (endp != str) && (errno == 0);
  196. }
  197. bool cmStrToULongLong(std::string const& str, unsigned long long* value)
  198. {
  199. return cmStrToULongLong(str.c_str(), value);
  200. }
  201. std::string cmJoin(std::vector<std::string> const& rng,
  202. cm::string_view separator, cm::string_view initial)
  203. {
  204. return cmJoinStrings(rng, separator, initial);
  205. }
  206. std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
  207. cm::string_view initial)
  208. {
  209. return cmJoinStrings(rng, separator, initial);
  210. }