C++11 library providing functionality common to all adapters.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
8.8 KiB

  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. #include "std_utils.hh"
  4. #include <iostream>
  5. #include <fstream>
  6. #include <cstdio>
  7. #include <cerrno>
  8. #include <cmath>
  9. #include <algorithm>
  10. #include <thread>
  11. #include <random>
  12. #include <cstring>
  13. #ifndef WIN32
  14. #include <dirent.h>
  15. #include <sys/stat.h>
  16. #endif
  17. using namespace std;
  18. using namespace pEp;
  19. namespace pEp {
  20. namespace Utils {
  21. bool is_c_str_empty(const char *str)
  22. {
  23. if (str == nullptr) {
  24. return true;
  25. }
  26. string tmp{ str };
  27. if (tmp.empty()) {
  28. return true;
  29. }
  30. return false;
  31. }
  32. string nested_exception_to_string(const exception &e, int level, string src)
  33. {
  34. src += string(level, ' ') + "exception: " + e.what() + "\n";
  35. try {
  36. rethrow_if_nested(e);
  37. } catch (const exception &e) {
  38. src = nested_exception_to_string(e, level + 1, src);
  39. } catch (...) {
  40. }
  41. return src;
  42. }
  43. // File utils
  44. bool path_exists(const string &filename)
  45. {
  46. ifstream ifile(filename.c_str());
  47. return (bool)ifile;
  48. }
  49. void path_delete(const string &filename)
  50. {
  51. int status = remove(filename.c_str());
  52. if (status) {
  53. runtime_error e{ string("path_delete(\"" + filename + "\") - " + strerror(errno)) };
  54. throw(e);
  55. }
  56. }
  57. #ifndef WIN32
  58. bool path_is_dir(const string &path)
  59. {
  60. bool ret = false;
  61. struct stat statbuf;
  62. if (stat(path.c_str(), &statbuf) != 0) {
  63. runtime_error e{ "path_is_dir(\"" + path + "\") - " + strerror(errno) };
  64. throw(e);
  65. }
  66. if (S_ISDIR(statbuf.st_mode)) {
  67. ret = true;
  68. }
  69. return ret;
  70. }
  71. void path_delete_all(const string &path)
  72. {
  73. try {
  74. if (!path_is_dir(path)) {
  75. path_delete(path);
  76. } else {
  77. vector<string> dirlist = dir_list_all(path);
  78. if (dirlist.empty()) {
  79. path_delete(path);
  80. } else {
  81. for (const string &filename : dirlist) {
  82. string newpath = path + "/" + filename;
  83. path_delete_all(newpath);
  84. }
  85. path_delete(path);
  86. }
  87. }
  88. } catch (...) {
  89. runtime_error e{ "path_delete_all(\"" + path + "\")" };
  90. throw_with_nested(e);
  91. }
  92. }
  93. #endif
  94. ofstream file_create(const string &filename)
  95. {
  96. ofstream outfile{ filename };
  97. return outfile;
  98. }
  99. std::string file_read(const std::string &filename)
  100. {
  101. auto ss = ostringstream{};
  102. ifstream input_file(filename);
  103. if (!input_file.is_open()) {
  104. runtime_error e{ "Could not open the file: " + filename };
  105. exit(EXIT_FAILURE);
  106. }
  107. ss << input_file.rdbuf();
  108. return ss.str();
  109. }
  110. #ifndef WIN32
  111. void path_ensure_not_existing(const string &path)
  112. {
  113. while (path_exists(path)) {
  114. path_delete_all(path);
  115. }
  116. }
  117. void dir_create(const string &dirname, const mode_t mode)
  118. {
  119. if (mkdir(dirname.c_str(), mode) != 0) {
  120. runtime_error e{ string("dir_create(\"" + dirname + "\") - " + strerror(errno)) };
  121. throw(e);
  122. }
  123. }
  124. void dir_ensure(const std::string &path)
  125. {
  126. if (!Utils::path_exists(path)) {
  127. Utils::dir_create(path);
  128. }
  129. }
  130. void dir_recreate(const std::string &path)
  131. {
  132. Utils::path_ensure_not_existing(path);
  133. Utils::dir_ensure(path);
  134. }
  135. vector<string> dir_list_all(const std::string &path, const bool incl_dot_and_dotdot)
  136. {
  137. vector<string> ret;
  138. if (!path_exists(path)) {
  139. runtime_error e{ "dir_list_all(\"" + path + "\") - Error: does not exist" };
  140. throw(e);
  141. }
  142. if (!path_is_dir(path)) {
  143. runtime_error e{ "dir_list_all(\"" + path + "\") - Error: is not a directory" };
  144. throw(e);
  145. }
  146. DIR *dirp = opendir(path.c_str());
  147. if (dirp == nullptr) {
  148. runtime_error e{ "dir_list_all(\"" + path + "\") - Error opening dir" };
  149. throw e;
  150. }
  151. struct dirent *dp;
  152. while ((dp = readdir(dirp)) != NULL) {
  153. ret.push_back(string(dp->d_name));
  154. }
  155. if (!incl_dot_and_dotdot) {
  156. ret.erase(
  157. remove_if(
  158. ret.begin(),
  159. ret.end(),
  160. [](string elem) { return (elem == "." || elem == ".."); }),
  161. ret.end());
  162. }
  163. closedir(dirp);
  164. return ret;
  165. }
  166. vector<string> dir_list_dirs(const string &dirname, const bool incl_dot_and_dotdot)
  167. {
  168. vector<string> ret = dir_list_all(dirname, incl_dot_and_dotdot);
  169. ret.erase(
  170. remove_if(
  171. ret.begin(),
  172. ret.end(),
  173. [dirname](string elem) { return !path_is_dir(dirname + "/" + elem); }),
  174. ret.end());
  175. return ret;
  176. }
  177. vector<string> dir_list_files(const string &dirname)
  178. {
  179. vector<string> ret = dir_list_all(dirname);
  180. ret.erase(
  181. remove_if(
  182. ret.begin(),
  183. ret.end(),
  184. [dirname](string elem) { return path_is_dir(dirname + "/" + elem); }),
  185. ret.end());
  186. return ret;
  187. }
  188. #endif
  189. // Attention, it pads left...
  190. string padTo(const string &str, const size_t num, const char paddingChar)
  191. {
  192. string ret{ str };
  193. if (num > ret.size()) {
  194. ret.insert(0, num - ret.size(), paddingChar);
  195. }
  196. return ret;
  197. }
  198. std::string clip(const std::string &str, const size_t len)
  199. {
  200. std::string ret{ str };
  201. if (str.length() > len) {
  202. ret = str.substr(0, len) + "...";
  203. }
  204. return ret;
  205. }
  206. // prints the beginning and the end of the string and clips out
  207. // content in the middle replaced by "... tldr ..."
  208. std::string tldr(const std::string &str, const size_t len)
  209. {
  210. std::string decoration = "...";
  211. int trunclen = len - decoration.length();
  212. std::string ret{ str };
  213. if (str.length() > len) {
  214. ret = "\n" + str.substr(0, (int)floor(trunclen / 2.0)) + "\n... tldr ...\n";
  215. ret += str.substr(str.length() - (int)floor(trunclen / 2.0), str.length());
  216. }
  217. return ret;
  218. }
  219. string to_termcol(const Color &col)
  220. {
  221. switch (col) {
  222. case Color::RESET:
  223. return "\033[0m";
  224. case Color::BLACK:
  225. return "\033[30m";
  226. case Color::RED:
  227. return "\033[31m";
  228. case Color::GREEN:
  229. return "\033[32m";
  230. case Color::YELLOW:
  231. return "\033[33m";
  232. case Color::BLUE:
  233. return "\033[34m";
  234. case Color::MAGENTA:
  235. return "\033[35m";
  236. case Color::CYAN:
  237. return "\033[36m";
  238. case Color::WHITE:
  239. return "\033[37m";
  240. default:
  241. return "\033[0m";
  242. }
  243. }
  244. void sleep_millis(int milis)
  245. {
  246. std::chrono::milliseconds timespan(milis);
  247. std::this_thread::sleep_for(timespan);
  248. }
  249. unsigned char random_char(unsigned char min, unsigned char max)
  250. {
  251. std::random_device rd;
  252. std::mt19937 gen(rd());
  253. std::uniform_int_distribution<short> dis(static_cast<short>(min), static_cast<short>(max));
  254. return static_cast<unsigned char>(dis(gen));
  255. }
  256. std::string random_string(unsigned char min, unsigned char max, int len)
  257. {
  258. std::stringstream ret;
  259. for (int i = 0; i < len; i++) {
  260. ret << random_char(97, 122);
  261. }
  262. return ret.str();
  263. }
  264. } // namespace Utils
  265. } // namespace pEp