utils.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #include "utils.h"
  2. #include <regex>
  3. #include <string>
  4. #include <vector>
  5. #include <exception>
  6. #include <chrono>
  7. /**
  8. * Clean up the trailing ../ in __FILE__
  9. *
  10. * This is used by the logging macro.
  11. *
  12. * @param filepath
  13. * @return const char*
  14. */
  15. const char *trim_path(const char *filepath) {
  16. if (strncmp(filepath, "../", 3) == 0) {
  17. filepath += 3;
  18. }
  19. return filepath;
  20. }
  21. #include <fstream>
  22. bool file_exists(const std::string &name) {
  23. std::ifstream f(name.c_str());
  24. return f.good();
  25. }
  26. bool replace(std::string &str, const std::string &from, const std::string &to) {
  27. size_t start_pos = str.find(from);
  28. if (start_pos == std::string::npos) return false;
  29. do {
  30. str.replace(start_pos, from.length(), to);
  31. } while ((start_pos = str.find(from)) != std::string::npos);
  32. return true;
  33. }
  34. bool replace(std::string &str, const char *from, const char *to) {
  35. size_t start_pos = str.find(from);
  36. if (start_pos == std::string::npos) return false;
  37. do {
  38. str.replace(start_pos, strlen(from), to);
  39. } while ((start_pos = str.find(from)) != std::string::npos);
  40. return true;
  41. }
  42. void ansi_clean(std::string &str) {
  43. static std::regex ansi_cleaner("\x1b\[[0-9;]*[A-Zmh]",
  44. std::regex_constants::ECMAScript);
  45. str = std::regex_replace(str, ansi_cleaner, "");
  46. }
  47. void high_ascii(std::string &str) {
  48. // the + replaces all of them into one. I want each high ascii replaced with
  49. // #.
  50. static std::regex high_cleaner("[\x80-\xff]",
  51. std::regex_constants::ECMAScript);
  52. str = std::regex_replace(str, high_cleaner, "#");
  53. }
  54. std::smatch ansi_newline(const std::string &str) {
  55. static std::regex ansi_nl("\x1b\[[0-9;]*[JK]",
  56. std::regex_constants::ECMAScript);
  57. std::smatch m;
  58. std::regex_search(str, m, ansi_nl);
  59. return m;
  60. }
  61. std::string repr(const std::string &source) {
  62. std::string output = source;
  63. replace(output, "\n", "\\n");
  64. replace(output, "\r", "\\r");
  65. replace(output, "\b", "\\b");
  66. replace(output, "\x1b", "\\[");
  67. high_ascii(output);
  68. return output;
  69. }
  70. std::string clean_string(const std::string &source) {
  71. std::string clean = source;
  72. /*
  73. replace(clean, "\n", "\\n");
  74. replace(clean, "\r", "\\r");
  75. replace(clean, "\b", "\\b");
  76. replace(clean, "\x1b", "\\[");
  77. */
  78. replace(clean, "\n", "");
  79. replace(clean, "\r", "");
  80. // ANSI too
  81. ansi_clean(clean);
  82. // BUGZ_LOG(error) << "cleaned: " << clean;
  83. high_ascii(clean);
  84. // replace(clean, "\x1b", "^");
  85. return clean;
  86. }
  87. std::vector<std::string> split(const std::string &line) {
  88. static std::regex rx_split("[^\\s]+");
  89. std::vector<std::string> results;
  90. for (auto it = std::sregex_iterator(line.begin(), line.end(), rx_split);
  91. it != std::sregex_iterator(); ++it) {
  92. results.push_back(it->str());
  93. }
  94. return results;
  95. }
  96. std::vector<std::string> split(const std::string &line, const std::string &by) {
  97. std::string work = line;
  98. std::vector<std::string> results;
  99. size_t pos;
  100. while ((pos = work.find(by)) != std::string::npos) {
  101. results.push_back(work.substr(0, pos));
  102. work.erase(0, pos + by.length());
  103. }
  104. if (!work.empty()) results.push_back(work);
  105. return results;
  106. }
  107. bool in(const std::string &line, const std::string &has) {
  108. return (line.find(has) != std::string::npos);
  109. }
  110. bool startswith(const std::string &line, const std::string &has) {
  111. return (line.substr(0, has.length()) == has);
  112. }
  113. bool endswith(const std::string &line, const std::string &has) {
  114. if (line.length() < has.length()) return false;
  115. return (line.substr(line.length() - has.length()) == has);
  116. }
  117. /**
  118. * Trim leading and trailing spaces from str.
  119. *
  120. * @param str
  121. */
  122. void trim(std::string &str) {
  123. while (str.substr(0, 1) == " ") str.erase(0, 1);
  124. while (str.substr(str.length() - 1) == " ") str.erase(str.length() - 1);
  125. }
  126. bool at_command_prompt(const std::string &prompt) {
  127. if (startswith(prompt, "Command ["))
  128. if (endswith(prompt, "] (?=Help)? : ")) return true;
  129. return false;
  130. }
  131. bool at_computer_prompt(const std::string &prompt) {
  132. if (startswith(prompt, "Computer command ["))
  133. if (endswith(prompt, "] (?=Help)? ")) return true;
  134. return false;
  135. }
  136. bool at_planet_prompt(const std::string &prompt) {
  137. if (startswith(prompt, "Planet command (?=Help)"))
  138. if (endswith(prompt, " [D] ")) return true;
  139. return false;
  140. }
  141. bool density_clear(int sector, int density, int navhaz) {
  142. if (sector == 0) return false;
  143. // if(anomoly) return false;
  144. /*
  145. http://wiki.classictw.com/index.php?title=Gypsy%27s_Big_Dummy%27s_Guide_to_TradeWars_Text#Trader_Information
  146. Density Readings:
  147. 0 = Empty Sector or Ferrengi Dreadanought
  148. 1 = Marker Beacon
  149. 2 = Limpet Type 2 Tracking Mine
  150. 5 = Fighter (per Fighter)
  151. 10 = Armid Type 1 Mine
  152. 21 = Navigation Hazard (Per 1 Percent)
  153. 21 = Destroyed Ship (Due to 1 Percent Nav-Haz)
  154. 38 = Unmanned Ship
  155. 40 = Manned Ship, Alien or Ferrengi Assault Trader
  156. 50 = Destroyed Starport (After 25 Percent Nav-Haz Clears)
  157. 100 = Starport or Ferrengi Battle Cruiser
  158. 210 = Destroyed Planet (Due to 10 Percent Nav-Haz)
  159. 462 = Federation Starship under Admiral Nelson
  160. 489 = Federation Starship under Captain Zyrain
  161. 500 = Planet
  162. 512 = Federation Starship under Admiral Clausewitz
  163. 575 = Destroyed Port (Before 25% Nav-Haz Clears)
  164. */
  165. int dense = density;
  166. if ((navhaz != 0) && (navhaz <= 5)) {
  167. // Adjust density by upto 5% navhaz, exlude greather than 5%
  168. dense -= navhaz * 21;
  169. }
  170. if (navhaz > 5) return false;
  171. switch (dense) {
  172. case 0:
  173. case 1:
  174. case 100:
  175. case 101:
  176. return true;
  177. }
  178. // Special case for Sector 001.
  179. if ((sector == 1) && (dense == 601)) return true;
  180. return false;
  181. }
  182. #include <algorithm>
  183. #include <cctype>
  184. void str_toupper(std::string &str) {
  185. std::transform(str.begin(), str.end(), str.begin(), ::toupper);
  186. }
  187. void str_tolower(std::string &str) {
  188. std::transform(str.begin(), str.end(), str.begin(), ::tolower);
  189. }
  190. void remove_telnet_commands(std::string &text) {
  191. size_t pos;
  192. while ((pos = text.find('\xff')) != std::string::npos) {
  193. text.erase(pos, pos + 3);
  194. }
  195. }
  196. int sstoi(const std::string &text, int failure) {
  197. int result;
  198. try {
  199. result = stoi(text);
  200. } catch (const std::invalid_argument &e) {
  201. // BUGZ_LOG(fatal) << e.what();
  202. return failure;
  203. } catch (const std::out_of_range &e) {
  204. // BUGZ_LOG(fatal) << e.what();
  205. return failure;
  206. }
  207. return result;
  208. }
  209. time_t time_t_now(void) {
  210. return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
  211. }
  212. // json support functions
  213. bool json_bool(json j) {
  214. if (j.is_boolean()) {
  215. return j.get<bool>();
  216. }
  217. if (j.is_number_integer()) {
  218. return j.get<int>() == 1;
  219. }
  220. if (j.is_string()) {
  221. std::string temp = j.get<std::string>();
  222. char c = toupper(temp[0]);
  223. return ((c == 'Y') || (c == 'T'));
  224. }
  225. std::string error = "json_bool from ";
  226. error += j.type_name();
  227. throw std::range_error(error);
  228. }
  229. std::string json_str(json j) {
  230. if (j.is_string()) return j.get<std::string>();
  231. if (j.is_number_integer()) {
  232. return std::to_string(j.get<int>());
  233. }
  234. std::string error = "json_str from ";
  235. error += j.type_name();
  236. throw std::range_error(error);
  237. }
  238. int json_int(json j) {
  239. if (j.is_number_integer()) return j.get<int>();
  240. if (j.is_string()) return sstoi(j.get<std::string>());
  241. std::string error = "json_int from ";
  242. error += j.type_name();
  243. throw std::range_error(error);
  244. }