Utils.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "Utils.h"
  4. #include <cassert>
  5. #include <sstream>
  6. #ifdef _WIN32
  7. #include <windows.h>
  8. #else
  9. #include <dirent.h>
  10. #include <sys/stat.h>
  11. #endif
  12. using namespace std;
  13. string Trim(const string& str)
  14. {
  15. size_t trimStart = 0;
  16. size_t trimEnd = str.length();
  17. while (trimStart < trimEnd)
  18. {
  19. char c = str.c_str()[trimStart];
  20. if (c != ' ' && c != 9)
  21. break;
  22. ++trimStart;
  23. }
  24. while (trimEnd > trimStart)
  25. {
  26. char c = str.c_str()[trimEnd - 1];
  27. if (c != ' ' && c != 9)
  28. break;
  29. --trimEnd;
  30. }
  31. return str.substr(trimStart, trimEnd - trimStart);
  32. }
  33. string GetFileName(const string& path)
  34. {
  35. size_t pos = path.find_last_of("/");
  36. assert(pos != string::npos);
  37. return path.substr(pos + 1);
  38. }
  39. string CutToLast(const string& src, const string& value, bool inclusive)
  40. {
  41. size_t pos = src.find_last_of(value);
  42. if (pos == string::npos)
  43. return src;
  44. if (inclusive)
  45. return src.substr(pos + 1);
  46. return src.substr(pos + 1 - value.length());
  47. }
  48. string WithoutFileName(const string& path)
  49. {
  50. size_t pos = path.find_last_of("/");
  51. assert(pos != string::npos);
  52. return path.substr(0, pos);
  53. }
  54. bool StartsWith(const string& str, const string& value)
  55. {
  56. return str.rfind(value, 0) == 0;
  57. }
  58. bool EndsWith(const string& str, const string& value)
  59. {
  60. if (value.size() > str.size())
  61. return false;
  62. return equal(value.rbegin(), value.rend(), str.rbegin());
  63. }
  64. string GetFirstWord(const string& str)
  65. {
  66. size_t pos = str.find(' ');
  67. if (pos == string::npos)
  68. return str;
  69. return str.substr(0, pos);
  70. }
  71. string ReplaceAll(const string& src, const string& from, const string& to)
  72. {
  73. string ret;
  74. size_t lastPos = 0;
  75. size_t findPos = src.find(from, lastPos);
  76. while (findPos != string::npos)
  77. {
  78. ret.append(src, lastPos, findPos - lastPos);
  79. ret += to;
  80. lastPos = findPos + from.length();
  81. findPos = src.find(from, lastPos);
  82. }
  83. ret += src.substr(lastPos);
  84. return ret;
  85. }
  86. string RemoveAll(const string& src, const string& value)
  87. {
  88. return ReplaceAll(src, value, "");
  89. }
  90. string ReplaceFirst(const string& src, const string& from, const string& to)
  91. {
  92. size_t findPos = src.find(from, 0);
  93. if (findPos == string::npos)
  94. return src;
  95. return src.substr(0, findPos) + to + src.substr(findPos + from.length());
  96. }
  97. string RemoveFirst(const string& src, const string& value)
  98. {
  99. size_t findPos = src.find(value, 0);
  100. if (findPos == string::npos)
  101. return src;
  102. return src.substr(0, findPos) + src.substr(findPos + value.length());
  103. }
  104. vector<string> Split(const string& str, char delim)
  105. {
  106. stringstream ss(str);
  107. string item;
  108. vector<string> result;
  109. while (getline(ss, item, delim))
  110. result.push_back(move(item));
  111. return result;
  112. }
  113. vector<string> Split(const string& str, const string& delim)
  114. {
  115. vector<string> result;
  116. size_t lastPos = 0;
  117. size_t findPos = str.find(delim, lastPos);
  118. while (findPos != string::npos)
  119. {
  120. result.push_back(str.substr(lastPos, findPos - lastPos));
  121. lastPos = findPos + delim.length();
  122. findPos = str.find(delim, lastPos);
  123. }
  124. result.push_back(str.substr(lastPos));
  125. return result;
  126. }
  127. string CutStart(const string& str, const string& value)
  128. {
  129. if (!StartsWith(str, value))
  130. return str;
  131. return str.substr(value.length());
  132. }
  133. string CutEnd(const string& str, const string& value)
  134. {
  135. if (!EndsWith(str, value))
  136. return str;
  137. return str.substr(0, str.length() - value.length());
  138. }
  139. bool Contains(const string& str, const string& substr)
  140. {
  141. return str.find(substr) != string::npos;
  142. }
  143. bool Contains(const string& str, char c)
  144. {
  145. return str.find(c) != string::npos;
  146. }
  147. string FirstCharToLower(const string& str)
  148. {
  149. if (str.empty())
  150. return str;
  151. string result = str;
  152. result[0] = tolower(str[0]);
  153. return result;
  154. }
  155. string Join(const vector<string>& values, const string& separator)
  156. {
  157. string result;
  158. for (const string& value : values)
  159. {
  160. if (!result.empty())
  161. result += separator;
  162. result += value;
  163. }
  164. return result;
  165. }
  166. string JoinNonEmpty(const vector<string>& strings, const string& separator)
  167. {
  168. string result;
  169. for (const string& str : strings)
  170. {
  171. if (str.empty())
  172. continue;
  173. if (!result.empty())
  174. result += separator;
  175. result += str;
  176. }
  177. return result;
  178. }
  179. string ToIdentifier(const string& str)
  180. {
  181. string result = ReplaceAll(str, ", ", "_comma_");
  182. result = ReplaceAll(result, "<", "_leftAngleBracket_");
  183. result = ReplaceAll(result, ">", "_rightAngleBracket_");
  184. return result;
  185. }
  186. static string RemoveTrailingSlash(const string& pathName)
  187. {
  188. string ret = Trim(pathName);
  189. ret = ReplaceAll(ret, "\\", "/");
  190. ret = CutEnd(ret, "/");
  191. return ret;
  192. }
  193. static string GetParentPath(const string& path)
  194. {
  195. size_t pos = RemoveTrailingSlash(path).find_last_of("/");
  196. if (pos != string::npos)
  197. return path.substr(0, pos + 1);
  198. else
  199. return string();
  200. }
  201. // setlocale(LC_ALL, "en_US.utf8") is required
  202. wstring ToWide(const string& multi)
  203. {
  204. std::wstring ret;
  205. wchar_t w;
  206. mbstate_t mb{};
  207. size_t n = 0;
  208. size_t len = multi.length() + 1;
  209. while (size_t res = mbrtowc(&w, multi.c_str() + n, len - n, &mb))
  210. {
  211. if (res == static_cast<size_t>(-1) || res == static_cast<size_t>(-2))
  212. throw "Invalid encoding";
  213. n += res;
  214. ret += w;
  215. }
  216. return ret;
  217. }
  218. bool DirExists(const string& pathName)
  219. {
  220. #ifndef _WIN32
  221. // Always return true for the root directory
  222. if (pathName == "/")
  223. return true;
  224. #endif
  225. string fixedName = RemoveTrailingSlash(pathName);
  226. #ifdef _WIN32
  227. DWORD attributes = GetFileAttributesW(ToWide(fixedName).c_str());
  228. if (attributes == INVALID_FILE_ATTRIBUTES || !(attributes & FILE_ATTRIBUTE_DIRECTORY))
  229. return false;
  230. #else
  231. struct stat st {};
  232. if (stat(fixedName.c_str(), &st) || !(st.st_mode & S_IFDIR))
  233. return false;
  234. #endif
  235. return true;
  236. }
  237. bool CreateDir(const string& pathName)
  238. {
  239. // Create each of the parents if necessary
  240. string parentPath = GetParentPath(pathName);
  241. if (parentPath.length() > 1 && !DirExists(parentPath))
  242. {
  243. if (!CreateDir(parentPath))
  244. return false;
  245. }
  246. #ifdef _WIN32
  247. bool success = (CreateDirectoryW(ToWide(RemoveTrailingSlash(pathName)).c_str(), nullptr) == TRUE) ||
  248. (GetLastError() == ERROR_ALREADY_EXISTS);
  249. #else
  250. bool success = mkdir(RemoveTrailingSlash(pathName).c_str(), S_IRWXU) == 0 || errno == EEXIST;
  251. #endif
  252. return success;
  253. }