utils.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. #include "utils.h"
  2. #include <algorithm> // transform
  3. #include <fstream>
  4. #include <sstream>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <string>
  9. #include <time.h>
  10. // http://c-faq.com/lib/randrange.html
  11. int randint(int N) { return rand() / (RAND_MAX / N + 1); }
  12. // http://c-faq.com/lib/randrange.html
  13. // numbers in the range [M, N] could be generated with something like
  14. int randrange(int M, int N) {
  15. return M + rand() / (RAND_MAX / (N - M + 1) + 1);
  16. }
  17. /**
  18. * random_activate()
  19. *
  20. * Is a weight (1-10),
  21. * tests if random number is < weight * 10.
  22. *
  23. * So random_activate(9) happens more frequently
  24. * then random_activate(8) or lower.
  25. *
  26. * This probably needs to be fixed.
  27. * We need a better randint(RANGE) code.
  28. */
  29. int random_activate(int w) {
  30. int r = randint(100);
  31. if (r <= w) {
  32. return 1;
  33. };
  34. return 0;
  35. }
  36. /**
  37. * Display a repr of the given string.
  38. *
  39. * This converts most \n\r\v\f\t codes,
  40. * defaults to \xHH (hex value).
  41. */
  42. char *repr(const char *data) {
  43. static char buffer[40960];
  44. char *cp;
  45. strcpy(buffer, data);
  46. cp = buffer;
  47. while (*cp != 0) {
  48. char c = *cp;
  49. if (c == ' ') {
  50. cp++;
  51. continue;
  52. };
  53. /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'),
  54. * horizontal tab ('\t'), and vertical tab ('\v') */
  55. if (strchr("\f\n\r\t\v\?", c) != NULL) {
  56. memmove(cp + 1, cp, strlen(cp) + 1);
  57. *cp = '\\';
  58. cp++;
  59. switch (c) {
  60. case '\f':
  61. *cp = 'f';
  62. cp++;
  63. break;
  64. case '\n':
  65. *cp = 'n';
  66. cp++;
  67. break;
  68. case '\r':
  69. *cp = 'r';
  70. cp++;
  71. break;
  72. case '\t':
  73. *cp = 't';
  74. cp++;
  75. break;
  76. case '\v':
  77. *cp = 'v';
  78. cp++;
  79. break;
  80. default:
  81. *cp = '?';
  82. cp++;
  83. break;
  84. }
  85. continue;
  86. }
  87. if (c == '\\') {
  88. memmove(cp + 1, cp, strlen(cp) + 1);
  89. *cp = '\\';
  90. cp += 2;
  91. continue;
  92. }
  93. if (c == '"') {
  94. memmove(cp + 1, cp, strlen(cp) + 1);
  95. *cp = '\\';
  96. cp += 2;
  97. continue;
  98. }
  99. if (strchr("[()]{}:;,.<>?!@#$%^&*", c) != NULL) {
  100. cp++;
  101. continue;
  102. }
  103. if (strchr("0123456789", c) != NULL) {
  104. cp++;
  105. continue;
  106. }
  107. if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c) !=
  108. NULL) {
  109. cp++;
  110. continue;
  111. }
  112. // Ok, default to \xHH output.
  113. memmove(cp + 3, cp, strlen(cp) + 1);
  114. char buffer[10];
  115. // int slen =
  116. snprintf(buffer, sizeof(buffer), "\\x%02x", (int)c & 0xff);
  117. /*
  118. if (slen >= sizeof(buffer)) {
  119. ZF_LOGE("snprintf %d > size %d", slen, (int)sizeof(buffer));
  120. }
  121. */
  122. strncpy(cp, buffer, 4);
  123. cp += 4;
  124. continue;
  125. }
  126. return buffer;
  127. }
  128. /*
  129. * strnstr()
  130. *
  131. * buffer safe version that looks for a string.
  132. */
  133. const char *strnstr(const char *source, int len, const char *needle) {
  134. int pos;
  135. for (pos = 0; pos < len; pos++) {
  136. if (source[pos] == needle[0]) {
  137. if (strncmp(source + pos, needle, strlen(needle)) == 0) {
  138. return source + pos;
  139. }
  140. }
  141. }
  142. return NULL;
  143. }
  144. /*
  145. * rstrnstr() Reverse string find in a string
  146. *
  147. * This obeys the len, and handles nulls in buffer.
  148. * find is a c-string (null terminated)
  149. */
  150. int rstrnstr(const char *buffer, int len, const char *find) {
  151. int flen = strlen(find);
  152. if (len < flen) {
  153. // I can't find a string in a buffer smaller then it is!
  154. return -1;
  155. }
  156. int pos = len - flen;
  157. while (pos > 0) {
  158. if (buffer[pos] == find[0]) {
  159. // First chars match, check them all.
  160. if (strncmp(buffer + pos, find, flen) == 0) {
  161. return pos;
  162. }
  163. }
  164. pos--;
  165. }
  166. return -1;
  167. }
  168. /*
  169. * string_insert()
  170. * Inserts a string into a given position.
  171. * This safely checks to make sure the buffer isn't overrun.
  172. *
  173. * buffer is a c null terminated string.
  174. */
  175. int string_insert(char *buffer, size_t max_length, size_t pos,
  176. const char *insert) {
  177. /*
  178. assert(max_length > pos);
  179. assert(buffer != NULL);
  180. assert(insert != NULL);
  181. */
  182. if (pos >= max_length)
  183. return 0;
  184. if (buffer == NULL)
  185. return 0;
  186. if (insert == NULL)
  187. return 0;
  188. if (strlen(insert) == 0)
  189. return 0;
  190. if (pos > strlen(buffer))
  191. return 0;
  192. if (strlen(buffer) + strlen(insert) >= max_length) {
  193. /*
  194. ZF_LOGD("string_insert() failed inserting [%s]", repr(insert));
  195. */
  196. return 0;
  197. }
  198. memmove(buffer + pos + strlen(insert), buffer + pos,
  199. strlen(buffer + pos) + 1);
  200. // cp + strlen(display), cp, strlen(cp) + 1);
  201. strncpy(buffer + pos, insert, strlen(insert));
  202. // (cp, display, strlen(display));
  203. return 1; // success
  204. }
  205. void remove_all(std::string &str, char c) {
  206. str.erase(std::remove(str.begin(), str.end(), c), str.end());
  207. }
  208. int unicode_len(char choad) {
  209. /*
  210. return length of unicode sequence, or 0 if not a unicode.
  211. */
  212. // https://en.wikipedia.org/wiki/UTF-8
  213. // 110xxxxx
  214. if ((choad & 0xe0) == 0xc0) {
  215. // CHOAD!
  216. return 2;
  217. }
  218. // 1110xxxx
  219. if ((choad & 0xf0) == 0xe0) {
  220. return 3;
  221. }
  222. // 11110xxx
  223. if ((choad & 0xf8) == 0xf0) {
  224. return 4;
  225. }
  226. return 0;
  227. }
  228. /*
  229. Pascal String Copy. Copy from pascal string, to C String.
  230. First char is pascal string length. (Max 255).
  231. */
  232. void pcopy(char *pstring, char *str) {
  233. int len = (int)*pstring;
  234. strncpy(str, pstring + 1, len);
  235. str[len] = 0;
  236. }
  237. /*
  238. * tail file, return new lines of text.
  239. *
  240. * Only handles lines < 256 chars.
  241. * Does not handle if the file is closed/unlinked/...
  242. *
  243. */
  244. std::string &find_new_text(std::ifstream &infile,
  245. std::streampos &last_position) {
  246. static std::string line;
  247. line.clear();
  248. infile.seekg(0, std::ios::end);
  249. std::streampos filesize = infile.tellg();
  250. if (filesize == -1) {
  251. // Ok, we've failed somehow. Now what?
  252. // cout << "SNAP!";
  253. return line;
  254. }
  255. // check if the new file started
  256. // we don't detect if the file has been unlinked/reset
  257. if (filesize < last_position) {
  258. // cout << "reset! " << filesize << endl;
  259. last_position = 0;
  260. }
  261. while (last_position < filesize) {
  262. // this loop -- seems broken.
  263. // for (long n = last_position; n < filesize; n++) {
  264. infile.seekg(last_position, std::ios::beg);
  265. char test[256];
  266. infile.getline(test, sizeof(test));
  267. if (infile.eof()) {
  268. // We got EOF instead of something.
  269. // Seek back to our last, good, known position
  270. // and exit (wait for the rest of the line)
  271. infile.seekg(last_position, std::ios::beg);
  272. return line;
  273. }
  274. std::streampos new_pos = infile.tellg();
  275. if (new_pos == -1)
  276. return line;
  277. last_position = new_pos;
  278. line.assign(test);
  279. return line;
  280. }
  281. return line;
  282. }
  283. void string_toupper(std::string &str) {
  284. std::transform(str.begin(), str.end(), str.begin(), ::toupper);
  285. }
  286. void string_trim(std::string &value) {
  287. while (*value.begin() == ' ')
  288. value.erase(value.begin());
  289. while (*(value.end() - 1) == ' ')
  290. value.erase(value.end() - 1);
  291. }
  292. std::map<std::string, std::string> read_configfile(std::string filename) {
  293. std::ifstream file(filename);
  294. std::string line;
  295. std::map<std::string, std::string> config;
  296. if (!file.is_open())
  297. return config;
  298. while (std::getline(file, line)) {
  299. if ((line[0] == '#') || (line[0] == ';'))
  300. continue;
  301. if (line.empty())
  302. continue;
  303. // I'm not so sure this part is very good.
  304. std::istringstream is_line(line);
  305. std::string key;
  306. if (std::getline(is_line, key, '=')) {
  307. string_trim(key);
  308. string_toupper(key);
  309. std::string value;
  310. if (std::getline(is_line, value)) {
  311. string_trim(value);
  312. config[key] = value;
  313. /*
  314. std::cout << "Key: [" << key << "] Value: [" << value << "]"
  315. << std::endl;
  316. */
  317. }
  318. }
  319. }
  320. return config;
  321. }
  322. bool replace(std::string &str, const std::string &from, const std::string &to) {
  323. size_t start_pos = str.find(from);
  324. if (start_pos == std::string::npos)
  325. return false;
  326. str.replace(start_pos, from.length(), to);
  327. return true;
  328. }
  329. IConv::IConv(const char *to, const char *from) : ic(iconv_open(to, from)) {}
  330. IConv::~IConv() { iconv_close(ic); }
  331. int IConv::convert(char *input, char *output, size_t outbufsize) {
  332. size_t inbufsize = strlen(input);
  333. // size_t orig_size = outbufsize;
  334. // memset(output, 0, outbufsize);
  335. // https://www.gnu.org/savannah-checkouts/gnu/libiconv/documentation/libiconv-1.15/iconv.3.html
  336. int r = iconv(ic, &input, &inbufsize, &output, &outbufsize);
  337. *output = 0;
  338. return r;
  339. }
  340. static IConv converter("UTF-8", "CP437");
  341. static time_t last_time = 0;
  342. std::map<std::string, std::string> CONFIG = read_configfile("hharry.cfg");
  343. /*
  344. * harry_level:
  345. *
  346. * 0 - inactive
  347. * 1 - Week 1 (1-7)
  348. * 2 - Week 2 (8-14)
  349. * 3 - Week 3 (15-21)
  350. * 4 - Week 4 (22-31)
  351. */
  352. int harry_level(void) {
  353. struct tm *tmp;
  354. time_t now = time(NULL);
  355. static int last = 0;
  356. auto search = CONFIG.find("LEVEL");
  357. if (search != CONFIG.end()) {
  358. last = stoi(search->second);
  359. if (last > 4) {
  360. last = 4;
  361. }
  362. if (last < 0) {
  363. last = 0;
  364. }
  365. return last;
  366. }
  367. if (last_time < now + 10) {
  368. last_time = now;
  369. // Do our every 10 second checks here
  370. tmp = gmtime(&now);
  371. if (tmp->tm_mon != 9)
  372. return (last = 0);
  373. if (tmp->tm_mday < 8)
  374. return (last = 1);
  375. if (tmp->tm_mday < 15)
  376. return (last = 2);
  377. if (tmp->tm_mday < 22)
  378. return (last = 3);
  379. return (last = 4);
  380. }
  381. return last;
  382. }
  383. /*
  384. * This is similar to repr, but --
  385. *
  386. * It converts high ASCII to UTF8, so it will display correctly
  387. * in the logfiles!
  388. */
  389. const char *logrepr(const char *input) {
  390. static char buffer[10240];
  391. char *cp;
  392. strcpy(buffer, input);
  393. cp = buffer;
  394. while (*cp != 0) {
  395. unsigned char c = *cp;
  396. if (c == ' ') {
  397. cp++;
  398. continue;
  399. };
  400. /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'),
  401. * horizontal tab ('\t'), and vertical tab ('\v') */
  402. if (strchr("\f\n\r\t\v", c) != NULL) {
  403. memmove(cp + 1, cp, strlen(cp) + 1);
  404. *cp = '\\';
  405. cp++;
  406. switch (c) {
  407. case '\f':
  408. *cp = 'f';
  409. cp++;
  410. break;
  411. case '\n':
  412. *cp = 'n';
  413. cp++;
  414. break;
  415. case '\r':
  416. *cp = 'r';
  417. cp++;
  418. break;
  419. case '\t':
  420. *cp = 't';
  421. cp++;
  422. break;
  423. case '\v':
  424. *cp = 'v';
  425. cp++;
  426. break;
  427. /* default:
  428. *cp = '?';
  429. cp++;
  430. break; */
  431. }
  432. continue;
  433. }
  434. if (c == '\\') {
  435. memmove(cp + 1, cp, strlen(cp) + 1);
  436. *cp = '\\';
  437. cp += 2;
  438. continue;
  439. }
  440. if (c == '"') {
  441. memmove(cp + 1, cp, strlen(cp) + 1);
  442. *cp = '\\';
  443. cp += 2;
  444. continue;
  445. }
  446. if (strchr("[()]{}:;,.<>?!@#$%^&*", c) != NULL) {
  447. cp++;
  448. continue;
  449. }
  450. if (strchr("0123456789", c) != NULL) {
  451. cp++;
  452. continue;
  453. }
  454. if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c) !=
  455. NULL) {
  456. cp++;
  457. continue;
  458. }
  459. if ((int)c < 0x20) {
  460. // Ok, default to \xHH output.
  461. memmove(cp + 3, cp, strlen(cp) + 1);
  462. char buffer[10];
  463. // int slen =
  464. snprintf(buffer, sizeof(buffer), "\\x%02x", (int)c & 0xff);
  465. strncpy(cp, buffer, 4);
  466. cp += 4;
  467. continue;
  468. };
  469. cp++;
  470. continue;
  471. }
  472. static char fancybuffer[16384];
  473. converter.convert(buffer, fancybuffer, sizeof(fancybuffer));
  474. return fancybuffer;
  475. }