cmStringAlgorithms.cxx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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 <cstdio>
  6. #include <errno.h>
  7. #include <stdlib.h>
  8. std::string cmTrimWhitespace(cm::string_view str)
  9. {
  10. auto start = str.begin();
  11. while (start != str.end() && cmIsSpace(*start)) {
  12. ++start;
  13. }
  14. if (start == str.end()) {
  15. return std::string();
  16. }
  17. auto stop = str.end() - 1;
  18. while (cmIsSpace(*stop)) {
  19. --stop;
  20. }
  21. return std::string(start, stop + 1);
  22. }
  23. std::string cmRemoveQuotes(cm::string_view str)
  24. {
  25. // We process only strings that have two quotes at least.
  26. // Also front() and back() are only defined behavior on non empty strings.
  27. if (str.size() >= 2 && //
  28. str.front() == '"' && //
  29. str.back() == '"') {
  30. // Remove a quote from the front and back
  31. str.remove_prefix(1);
  32. str.remove_suffix(1);
  33. }
  34. return std::string(str);
  35. }
  36. std::string cmEscapeQuotes(cm::string_view str)
  37. {
  38. std::string result;
  39. result.reserve(str.size());
  40. for (const char ch : str) {
  41. if (ch == '"') {
  42. result += '\\';
  43. }
  44. result += ch;
  45. }
  46. return result;
  47. }
  48. std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep)
  49. {
  50. std::vector<std::string> tokens;
  51. cm::string_view::size_type tokend = 0;
  52. do {
  53. cm::string_view::size_type tokstart = str.find_first_not_of(sep, tokend);
  54. if (tokstart == cm::string_view::npos) {
  55. break; // no more tokens
  56. }
  57. tokend = str.find_first_of(sep, tokstart);
  58. if (tokend == cm::string_view::npos) {
  59. tokens.emplace_back(str.substr(tokstart));
  60. } else {
  61. tokens.emplace_back(str.substr(tokstart, tokend - tokstart));
  62. }
  63. } while (tokend != cm::string_view::npos);
  64. if (tokens.empty()) {
  65. tokens.emplace_back();
  66. }
  67. return tokens;
  68. }
  69. void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut,
  70. bool emptyArgs)
  71. {
  72. // If argument is empty, it is an empty list.
  73. if (!emptyArgs && arg.empty()) {
  74. return;
  75. }
  76. // if there are no ; in the name then just copy the current string
  77. if (arg.find(';') == cm::string_view::npos) {
  78. argsOut.emplace_back(arg);
  79. return;
  80. }
  81. std::string newArg;
  82. // Break the string at non-escaped semicolons not nested in [].
  83. int squareNesting = 0;
  84. cm::string_view::iterator last = arg.begin();
  85. cm::string_view::iterator const cend = arg.end();
  86. for (cm::string_view::iterator c = last; c != cend; ++c) {
  87. switch (*c) {
  88. case '\\': {
  89. // We only want to allow escaping of semicolons. Other
  90. // escapes should not be processed here.
  91. cm::string_view::iterator cnext = c + 1;
  92. if ((cnext != cend) && *cnext == ';') {
  93. newArg.append(last, c);
  94. // Skip over the escape character
  95. last = cnext;
  96. c = cnext;
  97. }
  98. } break;
  99. case '[': {
  100. ++squareNesting;
  101. } break;
  102. case ']': {
  103. --squareNesting;
  104. } break;
  105. case ';': {
  106. // Break the string here if we are not nested inside square
  107. // brackets.
  108. if (squareNesting == 0) {
  109. newArg.append(last, c);
  110. // Skip over the semicolon
  111. last = c + 1;
  112. if (!newArg.empty() || emptyArgs) {
  113. // Add the last argument if the string is not empty.
  114. argsOut.push_back(newArg);
  115. newArg.clear();
  116. }
  117. }
  118. } break;
  119. default: {
  120. // Just append this character.
  121. } break;
  122. }
  123. }
  124. newArg.append(last, cend);
  125. if (!newArg.empty() || emptyArgs) {
  126. // Add the last argument if the string is not empty.
  127. argsOut.push_back(std::move(newArg));
  128. }
  129. }
  130. std::vector<std::string> cmExpandedList(cm::string_view arg, bool emptyArgs)
  131. {
  132. std::vector<std::string> argsOut;
  133. cmExpandList(arg, argsOut, emptyArgs);
  134. return argsOut;
  135. }
  136. namespace {
  137. template <std::size_t N, typename T>
  138. inline void MakeDigits(cm::string_view& view, char (&digits)[N],
  139. const char* pattern, T value)
  140. {
  141. int res = std::snprintf(digits, N, pattern, value);
  142. if (res > 0 && res < static_cast<int>(N)) {
  143. view = cm::string_view(digits, static_cast<std::size_t>(res));
  144. }
  145. }
  146. } // unnamed namespace
  147. cmAlphaNum::cmAlphaNum(int val)
  148. {
  149. MakeDigits(View_, Digits_, "%i", val);
  150. }
  151. cmAlphaNum::cmAlphaNum(unsigned int val)
  152. {
  153. MakeDigits(View_, Digits_, "%u", val);
  154. }
  155. cmAlphaNum::cmAlphaNum(long int val)
  156. {
  157. MakeDigits(View_, Digits_, "%li", val);
  158. }
  159. cmAlphaNum::cmAlphaNum(unsigned long int val)
  160. {
  161. MakeDigits(View_, Digits_, "%lu", val);
  162. }
  163. cmAlphaNum::cmAlphaNum(long long int val)
  164. {
  165. MakeDigits(View_, Digits_, "%lli", val);
  166. }
  167. cmAlphaNum::cmAlphaNum(unsigned long long int val)
  168. {
  169. MakeDigits(View_, Digits_, "%llu", val);
  170. }
  171. cmAlphaNum::cmAlphaNum(float val)
  172. {
  173. MakeDigits(View_, Digits_, "%g", static_cast<double>(val));
  174. }
  175. cmAlphaNum::cmAlphaNum(double val)
  176. {
  177. MakeDigits(View_, Digits_, "%g", val);
  178. }
  179. std::string cmCatViews(std::initializer_list<cm::string_view> views)
  180. {
  181. std::size_t total_size = 0;
  182. for (cm::string_view const& view : views) {
  183. total_size += view.size();
  184. }
  185. std::string result(total_size, '\0');
  186. std::string::iterator sit = result.begin();
  187. for (cm::string_view const& view : views) {
  188. sit = std::copy_n(view.data(), view.size(), sit);
  189. }
  190. return result;
  191. }
  192. bool cmStrToLong(const char* str, long* value)
  193. {
  194. errno = 0;
  195. char* endp;
  196. *value = strtol(str, &endp, 10);
  197. return (*endp == '\0') && (endp != str) && (errno == 0);
  198. }
  199. bool cmStrToLong(std::string const& str, long* value)
  200. {
  201. return cmStrToLong(str.c_str(), value);
  202. }
  203. bool cmStrToULong(const char* str, unsigned long* value)
  204. {
  205. errno = 0;
  206. char* endp;
  207. while (cmIsSpace(*str)) {
  208. ++str;
  209. }
  210. if (*str == '-') {
  211. return false;
  212. }
  213. *value = strtoul(str, &endp, 10);
  214. return (*endp == '\0') && (endp != str) && (errno == 0);
  215. }
  216. bool cmStrToULong(std::string const& str, unsigned long* value)
  217. {
  218. return cmStrToULong(str.c_str(), value);
  219. }