PageRenderTime 50ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/crnlib/crn_strutils.cpp

https://gitlab.com/BoTranVan/crunch
C++ | 613 lines | 470 code | 140 blank | 3 comment | 117 complexity | 701c7e6757fbe724325b5aa7fc1a7ddd MD5 | raw file
  1. // File: crn_strutils.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_strutils.h"
  5. namespace crnlib
  6. {
  7. char* crn_strdup(const char* pStr)
  8. {
  9. if (!pStr)
  10. pStr = "";
  11. size_t l = strlen(pStr) + 1;
  12. char *p = (char *)crnlib_malloc(l);
  13. if (p)
  14. memcpy(p, pStr, l);
  15. return p;
  16. }
  17. int crn_stricmp(const char *p, const char *q)
  18. {
  19. return _stricmp(p, q);
  20. }
  21. char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc)
  22. {
  23. CRNLIB_ASSERT(pDst && pSrc && dst_len);
  24. if (!dst_len)
  25. return pDst;
  26. char* q = pDst;
  27. char c;
  28. do
  29. {
  30. if (dst_len == 1)
  31. {
  32. *q++ = '\0';
  33. break;
  34. }
  35. c = *pSrc++;
  36. *q++ = c;
  37. dst_len--;
  38. } while (c);
  39. CRNLIB_ASSERT((q - pDst) <= (int)dst_len);
  40. return pDst;
  41. }
  42. bool int_to_string(int value, char* pDst, uint len)
  43. {
  44. CRNLIB_ASSERT(pDst);
  45. const uint cBufSize = 16;
  46. char buf[cBufSize];
  47. uint j = static_cast<uint>((value < 0) ? -value : value);
  48. char* p = buf + cBufSize - 1;
  49. *p-- = '\0';
  50. do
  51. {
  52. *p-- = static_cast<uint8>('0' + (j % 10));
  53. j /= 10;
  54. } while (j);
  55. if (value < 0)
  56. *p-- = '-';
  57. const size_t total_bytes = (buf + cBufSize - 1) - p;
  58. if (total_bytes > len)
  59. return false;
  60. for (size_t i = 0; i < total_bytes; i++)
  61. pDst[i] = p[1 + i];
  62. return true;
  63. }
  64. bool uint_to_string(uint value, char* pDst, uint len)
  65. {
  66. CRNLIB_ASSERT(pDst);
  67. const uint cBufSize = 16;
  68. char buf[cBufSize];
  69. char* p = buf + cBufSize - 1;
  70. *p-- = '\0';
  71. do
  72. {
  73. *p-- = static_cast<uint8>('0' + (value % 10));
  74. value /= 10;
  75. } while (value);
  76. const size_t total_bytes = (buf + cBufSize - 1) - p;
  77. if (total_bytes > len)
  78. return false;
  79. for (size_t i = 0; i < total_bytes; i++)
  80. pDst[i] = p[1 + i];
  81. return true;
  82. }
  83. bool string_to_int(const char*& pBuf, int& value)
  84. {
  85. value = 0;
  86. CRNLIB_ASSERT(pBuf);
  87. const char* p = pBuf;
  88. while (*p && isspace(*p))
  89. p++;
  90. uint result = 0;
  91. bool negative = false;
  92. if (!isdigit(*p))
  93. {
  94. if (p[0] == '-')
  95. {
  96. negative = true;
  97. p++;
  98. }
  99. else
  100. return false;
  101. }
  102. while (*p && isdigit(*p))
  103. {
  104. if (result & 0xE0000000U)
  105. return false;
  106. const uint result8 = result << 3U;
  107. const uint result2 = result << 1U;
  108. if (result2 > (0xFFFFFFFFU - result8))
  109. return false;
  110. result = result8 + result2;
  111. uint c = p[0] - '0';
  112. if (c > (0xFFFFFFFFU - result))
  113. return false;
  114. result += c;
  115. p++;
  116. }
  117. if (negative)
  118. {
  119. if (result > 0x80000000U)
  120. {
  121. value = 0;
  122. return false;
  123. }
  124. value = -static_cast<int>(result);
  125. }
  126. else
  127. {
  128. if (result > 0x7FFFFFFFU)
  129. {
  130. value = 0;
  131. return false;
  132. }
  133. value = static_cast<int>(result);
  134. }
  135. pBuf = p;
  136. return true;
  137. }
  138. bool string_to_int64(const char*& pBuf, int64& value)
  139. {
  140. value = 0;
  141. CRNLIB_ASSERT(pBuf);
  142. const char* p = pBuf;
  143. while (*p && isspace(*p))
  144. p++;
  145. uint64 result = 0;
  146. bool negative = false;
  147. if (!isdigit(*p))
  148. {
  149. if (p[0] == '-')
  150. {
  151. negative = true;
  152. p++;
  153. }
  154. else
  155. return false;
  156. }
  157. while (*p && isdigit(*p))
  158. {
  159. if (result & 0xE000000000000000ULL)
  160. return false;
  161. const uint64 result8 = result << 3U;
  162. const uint64 result2 = result << 1U;
  163. if (result2 > (0xFFFFFFFFFFFFFFFFULL - result8))
  164. return false;
  165. result = result8 + result2;
  166. uint c = p[0] - '0';
  167. if (c > (0xFFFFFFFFFFFFFFFFULL - result))
  168. return false;
  169. result += c;
  170. p++;
  171. }
  172. if (negative)
  173. {
  174. if (result > 0x8000000000000000ULL)
  175. {
  176. value = 0;
  177. return false;
  178. }
  179. value = -static_cast<int64>(result);
  180. }
  181. else
  182. {
  183. if (result > 0x7FFFFFFFFFFFFFFFULL)
  184. {
  185. value = 0;
  186. return false;
  187. }
  188. value = static_cast<int64>(result);
  189. }
  190. pBuf = p;
  191. return true;
  192. }
  193. bool string_to_uint(const char*& pBuf, uint& value)
  194. {
  195. value = 0;
  196. CRNLIB_ASSERT(pBuf);
  197. const char* p = pBuf;
  198. while (*p && isspace(*p))
  199. p++;
  200. uint result = 0;
  201. if (!isdigit(*p))
  202. return false;
  203. while (*p && isdigit(*p))
  204. {
  205. if (result & 0xE0000000U)
  206. return false;
  207. const uint result8 = result << 3U;
  208. const uint result2 = result << 1U;
  209. if (result2 > (0xFFFFFFFFU - result8))
  210. return false;
  211. result = result8 + result2;
  212. uint c = p[0] - '0';
  213. if (c > (0xFFFFFFFFU - result))
  214. return false;
  215. result += c;
  216. p++;
  217. }
  218. value = result;
  219. pBuf = p;
  220. return true;
  221. }
  222. bool string_to_uint64(const char*& pBuf, uint64& value)
  223. {
  224. value = 0;
  225. CRNLIB_ASSERT(pBuf);
  226. const char* p = pBuf;
  227. while (*p && isspace(*p))
  228. p++;
  229. uint64 result = 0;
  230. if (!isdigit(*p))
  231. return false;
  232. while (*p && isdigit(*p))
  233. {
  234. if (result & 0xE000000000000000ULL)
  235. return false;
  236. const uint64 result8 = result << 3U;
  237. const uint64 result2 = result << 1U;
  238. if (result2 > (0xFFFFFFFFFFFFFFFFULL - result8))
  239. return false;
  240. result = result8 + result2;
  241. uint c = p[0] - '0';
  242. if (c > (0xFFFFFFFFFFFFFFFFULL - result))
  243. return false;
  244. result += c;
  245. p++;
  246. }
  247. value = result;
  248. pBuf = p;
  249. return true;
  250. }
  251. bool string_to_bool(const char* p, bool& value)
  252. {
  253. CRNLIB_ASSERT(p);
  254. value = false;
  255. if (_stricmp(p, "false") == 0)
  256. return true;
  257. if (_stricmp(p, "true") == 0)
  258. {
  259. value = true;
  260. return true;
  261. }
  262. const char* q = p;
  263. uint v;
  264. if (string_to_uint(q, v))
  265. {
  266. if (!v)
  267. return true;
  268. else if (v == 1)
  269. {
  270. value = true;
  271. return true;
  272. }
  273. }
  274. return false;
  275. }
  276. bool string_to_float(const char*& p, float& value, uint round_digit)
  277. {
  278. double d;
  279. if (!string_to_double(p, d, round_digit))
  280. {
  281. value = 0;
  282. return false;
  283. }
  284. value = static_cast<float>(d);
  285. return true;
  286. }
  287. bool string_to_double(const char*& p, double& value, uint round_digit)
  288. {
  289. return string_to_double(p, p + 128, value, round_digit);
  290. }
  291. // I wrote this approx. 20 years ago in C/assembly using a limited FP emulator package, so it's a bit crude.
  292. bool string_to_double(const char*& p, const char *pEnd, double& value, uint round_digit)
  293. {
  294. CRNLIB_ASSERT(p);
  295. value = 0;
  296. enum { AF_BLANK = 1, AF_SIGN = 2, AF_DPOINT = 3, AF_BADCHAR = 4, AF_OVRFLOW = 5, AF_EXPONENT = 6, AF_NODIGITS = 7 };
  297. int status = 0;
  298. const char* buf = p;
  299. int got_sign_flag = 0, got_dp_flag = 0, got_num_flag = 0;
  300. int got_e_flag = 0, got_e_sign_flag = 0, e_sign = 0;
  301. uint whole_count = 0, frac_count = 0;
  302. double whole = 0, frac = 0, scale = 1, exponent = 1;
  303. if (p >= pEnd)
  304. {
  305. status = AF_NODIGITS;
  306. goto af_exit;
  307. }
  308. while (*buf)
  309. {
  310. if (!isspace(*buf))
  311. break;
  312. if (++buf >= pEnd)
  313. {
  314. status = AF_NODIGITS;
  315. goto af_exit;
  316. }
  317. }
  318. p = buf;
  319. while (*buf)
  320. {
  321. p = buf;
  322. if (buf >= pEnd)
  323. break;
  324. int i = *buf++;
  325. switch (i)
  326. {
  327. case 'e':
  328. case 'E':
  329. {
  330. got_e_flag = 1;
  331. goto exit_while;
  332. }
  333. case '+':
  334. {
  335. if ((got_num_flag) || (got_sign_flag))
  336. {
  337. status = AF_SIGN;
  338. goto af_exit;
  339. }
  340. got_sign_flag = 1;
  341. break;
  342. }
  343. case '-':
  344. {
  345. if ((got_num_flag) || (got_sign_flag))
  346. {
  347. status = AF_SIGN;
  348. goto af_exit;
  349. }
  350. got_sign_flag = -1;
  351. break;
  352. }
  353. case '.':
  354. {
  355. if (got_dp_flag)
  356. {
  357. status = AF_DPOINT;
  358. goto af_exit;
  359. }
  360. got_dp_flag = 1;
  361. break;
  362. }
  363. default:
  364. {
  365. if ((i < '0') || (i > '9'))
  366. goto exit_while;
  367. else
  368. {
  369. i -= '0';
  370. got_num_flag = 1;
  371. if (got_dp_flag)
  372. {
  373. if (frac_count < round_digit)
  374. {
  375. frac = frac * 10.0f + i;
  376. scale = scale * 10.0f;
  377. }
  378. else if (frac_count == round_digit)
  379. {
  380. if (i >= 5) /* check for round */
  381. frac = frac + 1.0f;
  382. }
  383. frac_count++;
  384. }
  385. else
  386. {
  387. whole = whole * 10.0f + i;
  388. whole_count++;
  389. if (whole > 1e+100)
  390. {
  391. status = AF_OVRFLOW;
  392. goto af_exit;
  393. }
  394. }
  395. }
  396. break;
  397. }
  398. }
  399. }
  400. exit_while:
  401. if (got_e_flag)
  402. {
  403. if ((got_num_flag == 0) && (got_dp_flag))
  404. {
  405. status = AF_EXPONENT;
  406. goto af_exit;
  407. }
  408. int e = 0;
  409. e_sign = 1;
  410. got_num_flag = 0;
  411. got_e_sign_flag = 0;
  412. while (*buf)
  413. {
  414. p = buf;
  415. if (buf >= pEnd)
  416. break;
  417. int i = *buf++;
  418. if (i == '+')
  419. {
  420. if ((got_num_flag) || (got_e_sign_flag))
  421. {
  422. status = AF_EXPONENT;
  423. goto af_exit;
  424. }
  425. e_sign = 1;
  426. got_e_sign_flag = 1;
  427. }
  428. else if (i == '-')
  429. {
  430. if ((got_num_flag) || (got_e_sign_flag))
  431. {
  432. status = AF_EXPONENT;
  433. goto af_exit;
  434. }
  435. e_sign = -1;
  436. got_e_sign_flag = 1;
  437. }
  438. else if ((i >= '0') && (i <= '9'))
  439. {
  440. got_num_flag = 1;
  441. if ((e = (e * 10) + (i - 48)) > 100)
  442. {
  443. status = AF_EXPONENT;
  444. goto af_exit;
  445. }
  446. }
  447. else
  448. break;
  449. }
  450. for (int i = 1; i <= e; i++) /* compute 10^e */
  451. exponent = exponent * 10.0f;
  452. }
  453. if (((whole_count + frac_count) == 0) && (got_e_flag == 0))
  454. {
  455. status = AF_NODIGITS;
  456. goto af_exit;
  457. }
  458. if (frac)
  459. whole = whole + (frac / scale);
  460. if (got_e_flag)
  461. {
  462. if (e_sign > 0)
  463. whole = whole * exponent;
  464. else
  465. whole = whole / exponent;
  466. }
  467. if (got_sign_flag < 0)
  468. whole = -whole;
  469. value = whole;
  470. af_exit:
  471. return (status == 0);
  472. }
  473. } // namespace crnlib