string.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /*
  2. * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #include <bx/allocator.h>
  6. #include <bx/hash.h>
  7. #include <bx/readerwriter.h>
  8. #include <bx/string.h>
  9. #if !BX_CRT_NONE
  10. # include <stdio.h> // vsnprintf, vsnwprintf
  11. #endif // !BX_CRT_NONE
  12. namespace bx
  13. {
  14. bool isSpace(char _ch)
  15. {
  16. return ' ' == _ch
  17. || '\t' == _ch
  18. || '\n' == _ch
  19. || '\v' == _ch
  20. || '\f' == _ch
  21. || '\r' == _ch
  22. ;
  23. }
  24. bool isUpper(char _ch)
  25. {
  26. return _ch >= 'A' && _ch <= 'Z';
  27. }
  28. bool isLower(char _ch)
  29. {
  30. return _ch >= 'a' && _ch <= 'z';
  31. }
  32. bool isAlpha(char _ch)
  33. {
  34. return isLower(_ch) || isUpper(_ch);
  35. }
  36. bool isNumeric(char _ch)
  37. {
  38. return _ch >= '0' && _ch <= '9';
  39. }
  40. bool isAlphaNum(char _ch)
  41. {
  42. return isAlpha(_ch) || isNumeric(_ch);
  43. }
  44. bool isPrint(char _ch)
  45. {
  46. return isAlphaNum(_ch) || isSpace(_ch);
  47. }
  48. char toLower(char _ch)
  49. {
  50. return _ch + (isUpper(_ch) ? 0x20 : 0);
  51. }
  52. char toUpper(char _ch)
  53. {
  54. return _ch - (isLower(_ch) ? 0x20 : 0);
  55. }
  56. bool toBool(const char* _str)
  57. {
  58. char ch = toLower(_str[0]);
  59. return ch == 't' || ch == '1';
  60. }
  61. int32_t strncmp(const char* _lhs, const char* _rhs, size_t _max)
  62. {
  63. for (
  64. ; 0 < _max && *_lhs == *_rhs
  65. ; ++_lhs, ++_rhs, --_max
  66. )
  67. {
  68. if (*_lhs == '\0'
  69. || *_rhs == '\0')
  70. {
  71. break;
  72. }
  73. }
  74. return 0 == _max ? 0 : *_lhs - *_rhs;
  75. }
  76. int32_t strincmp(const char* _lhs, const char* _rhs, size_t _max)
  77. {
  78. for (
  79. ; 0 < _max && toLower(*_lhs) == toLower(*_rhs)
  80. ; ++_lhs, ++_rhs, --_max
  81. )
  82. {
  83. if (*_lhs == '\0'
  84. || *_rhs == '\0')
  85. {
  86. break;
  87. }
  88. }
  89. return 0 == _max ? 0 : *_lhs - *_rhs;
  90. }
  91. size_t strnlen(const char* _str, size_t _max)
  92. {
  93. const char* ptr;
  94. for (ptr = _str; 0 < _max && *ptr != '\0'; ++ptr, --_max) {};
  95. return ptr - _str;
  96. }
  97. size_t strlncpy(char* _dst, size_t _dstSize, const char* _src, size_t _num)
  98. {
  99. BX_CHECK(NULL != _dst, "_dst can't be NULL!");
  100. BX_CHECK(NULL != _src, "_src can't be NULL!");
  101. BX_CHECK(0 < _dstSize, "_dstSize can't be 0!");
  102. const size_t len = strnlen(_src, _num);
  103. const size_t max = _dstSize-1;
  104. const size_t num = (len < max ? len : max);
  105. memCopy(_dst, _src, num);
  106. _dst[num] = '\0';
  107. return num;
  108. }
  109. size_t strlncat(char* _dst, size_t _dstSize, const char* _src, size_t _num)
  110. {
  111. BX_CHECK(NULL != _dst, "_dst can't be NULL!");
  112. BX_CHECK(NULL != _src, "_src can't be NULL!");
  113. BX_CHECK(0 < _dstSize, "_dstSize can't be 0!");
  114. const size_t max = _dstSize;
  115. const size_t len = strnlen(_dst, max);
  116. return strlncpy(&_dst[len], max-len, _src, _num);
  117. }
  118. const char* strnchr(const char* _str, char _ch, size_t _max)
  119. {
  120. for (size_t ii = 0, len = strnlen(_str, _max); ii < len; ++ii)
  121. {
  122. if (_str[ii] == _ch)
  123. {
  124. return &_str[ii];
  125. }
  126. }
  127. return NULL;
  128. }
  129. const char* strnrchr(const char* _str, char _ch, size_t _max)
  130. {
  131. for (size_t ii = strnlen(_str, _max); 0 < ii; --ii)
  132. {
  133. if (_str[ii] == _ch)
  134. {
  135. return &_str[ii];
  136. }
  137. }
  138. return NULL;
  139. }
  140. const char* strnstr(const char* _str, const char* _find, size_t _max)
  141. {
  142. const char* ptr = _str;
  143. size_t stringLen = strnlen(_str, _max);
  144. const size_t findLen = strnlen(_find);
  145. for (; stringLen >= findLen; ++ptr, --stringLen)
  146. {
  147. // Find start of the string.
  148. while (*ptr != *_find)
  149. {
  150. ++ptr;
  151. --stringLen;
  152. // Search pattern lenght can't be longer than the string.
  153. if (findLen > stringLen)
  154. {
  155. return NULL;
  156. }
  157. }
  158. // Set pointers.
  159. const char* string = ptr;
  160. const char* search = _find;
  161. // Start comparing.
  162. while (*string++ == *search++)
  163. {
  164. // If end of the 'search' string is reached, all characters match.
  165. if ('\0' == *search)
  166. {
  167. return ptr;
  168. }
  169. }
  170. }
  171. return NULL;
  172. }
  173. const char* stristr(const char* _str, const char* _find, size_t _max)
  174. {
  175. const char* ptr = _str;
  176. size_t stringLen = strnlen(_str, _max);
  177. const size_t findLen = strnlen(_find);
  178. for (; stringLen >= findLen; ++ptr, --stringLen)
  179. {
  180. // Find start of the string.
  181. while (toLower(*ptr) != toLower(*_find) )
  182. {
  183. ++ptr;
  184. --stringLen;
  185. // Search pattern lenght can't be longer than the string.
  186. if (findLen > stringLen)
  187. {
  188. return NULL;
  189. }
  190. }
  191. // Set pointers.
  192. const char* string = ptr;
  193. const char* search = _find;
  194. // Start comparing.
  195. while (toLower(*string++) == toLower(*search++) )
  196. {
  197. // If end of the 'search' string is reached, all characters match.
  198. if ('\0' == *search)
  199. {
  200. return ptr;
  201. }
  202. }
  203. }
  204. return NULL;
  205. }
  206. const char* strnl(const char* _str)
  207. {
  208. for (; '\0' != *_str; _str += strnlen(_str, 1024) )
  209. {
  210. const char* eol = strnstr(_str, "\r\n", 1024);
  211. if (NULL != eol)
  212. {
  213. return eol + 2;
  214. }
  215. eol = strnstr(_str, "\n", 1024);
  216. if (NULL != eol)
  217. {
  218. return eol + 1;
  219. }
  220. }
  221. return _str;
  222. }
  223. const char* streol(const char* _str)
  224. {
  225. for (; '\0' != *_str; _str += strnlen(_str, 1024) )
  226. {
  227. const char* eol = strnstr(_str, "\r\n", 1024);
  228. if (NULL != eol)
  229. {
  230. return eol;
  231. }
  232. eol = strnstr(_str, "\n", 1024);
  233. if (NULL != eol)
  234. {
  235. return eol;
  236. }
  237. }
  238. return _str;
  239. }
  240. const char* strws(const char* _str)
  241. {
  242. for (; isSpace(*_str); ++_str) {};
  243. return _str;
  244. }
  245. const char* strnws(const char* _str)
  246. {
  247. for (; !isSpace(*_str); ++_str) {};
  248. return _str;
  249. }
  250. const char* strword(const char* _str)
  251. {
  252. for (char ch = *_str++; isAlphaNum(ch) || '_' == ch; ch = *_str++) {};
  253. return _str-1;
  254. }
  255. const char* strmb(const char* _str, char _open, char _close)
  256. {
  257. int count = 0;
  258. for (char ch = *_str++; ch != '\0' && count >= 0; ch = *_str++)
  259. {
  260. if (ch == _open)
  261. {
  262. count++;
  263. }
  264. else if (ch == _close)
  265. {
  266. count--;
  267. if (0 == count)
  268. {
  269. return _str-1;
  270. }
  271. }
  272. }
  273. return NULL;
  274. }
  275. void eolLF(char* _out, size_t _size, const char* _str)
  276. {
  277. if (0 < _size)
  278. {
  279. char* end = _out + _size - 1;
  280. for (char ch = *_str++; ch != '\0' && _out < end; ch = *_str++)
  281. {
  282. if ('\r' != ch)
  283. {
  284. *_out++ = ch;
  285. }
  286. }
  287. *_out = '\0';
  288. }
  289. }
  290. const char* findIdentifierMatch(const char* _str, const char* _word)
  291. {
  292. size_t len = strnlen(_word);
  293. const char* ptr = strnstr(_str, _word);
  294. for (; NULL != ptr; ptr = strnstr(ptr + len, _word) )
  295. {
  296. if (ptr != _str)
  297. {
  298. char ch = *(ptr - 1);
  299. if (isAlphaNum(ch) || '_' == ch)
  300. {
  301. continue;
  302. }
  303. }
  304. char ch = ptr[len];
  305. if (isAlphaNum(ch) || '_' == ch)
  306. {
  307. continue;
  308. }
  309. return ptr;
  310. }
  311. return ptr;
  312. }
  313. const char* findIdentifierMatch(const char* _str, const char* _words[])
  314. {
  315. for (const char* word = *_words; NULL != word; ++_words, word = *_words)
  316. {
  317. const char* match = findIdentifierMatch(_str, word);
  318. if (NULL != match)
  319. {
  320. return match;
  321. }
  322. }
  323. return NULL;
  324. }
  325. int32_t write(WriterI* _writer, const char* _format, va_list _argList, Error* _err);
  326. int32_t vsnprintfRef(char* _out, size_t _max, const char* _format, va_list _argList)
  327. {
  328. if (1 < _max)
  329. {
  330. StaticMemoryBlockWriter writer(_out, uint32_t(_max-1) );
  331. _out[_max-1] = '\0';
  332. Error err;
  333. va_list argListCopy;
  334. va_copy(argListCopy, _argList);
  335. int32_t size = write(&writer, _format, argListCopy, &err);
  336. va_end(argListCopy);
  337. if (err.isOk() )
  338. {
  339. return size;
  340. }
  341. }
  342. Error err;
  343. SizerWriter sizer;
  344. va_list argListCopy;
  345. va_copy(argListCopy, _argList);
  346. int32_t size = write(&sizer, _format, argListCopy, &err);
  347. va_end(argListCopy);
  348. return size - 1 /* size without '\0' terminator */;
  349. }
  350. int32_t vsnprintf(char* _out, size_t _max, const char* _format, va_list _argList)
  351. {
  352. #if BX_CRT_NONE
  353. return vsnprintfRef(_out, _max, _format, _argList);
  354. #elif BX_CRT_MSVC
  355. int32_t len = -1;
  356. if (NULL != _out)
  357. {
  358. va_list argListCopy;
  359. va_copy(argListCopy, _argList);
  360. len = ::vsnprintf_s(_out, _max, size_t(-1), _format, argListCopy);
  361. va_end(argListCopy);
  362. }
  363. return -1 == len ? ::_vscprintf(_format, _argList) : len;
  364. #else
  365. return ::vsnprintf(_out, _max, _format, _argList);
  366. #endif // BX_COMPILER_MSVC
  367. }
  368. int32_t snprintf(char* _out, size_t _max, const char* _format, ...)
  369. {
  370. va_list argList;
  371. va_start(argList, _format);
  372. int32_t len = vsnprintf(_out, _max, _format, argList);
  373. va_end(argList);
  374. return len;
  375. }
  376. int32_t vsnwprintf(wchar_t* _out, size_t _max, const wchar_t* _format, va_list _argList)
  377. {
  378. #if BX_CRT_NONE
  379. BX_UNUSED(_out, _max, _format, _argList);
  380. return 0;
  381. #elif BX_CRT_MSVC
  382. int32_t len = -1;
  383. if (NULL != _out)
  384. {
  385. va_list argListCopy;
  386. va_copy(argListCopy, _argList);
  387. len = ::_vsnwprintf_s(_out, _max, size_t(-1), _format, argListCopy);
  388. va_end(argListCopy);
  389. }
  390. return -1 == len ? ::_vscwprintf(_format, _argList) : len;
  391. #elif BX_CRT_MINGW
  392. return ::vsnwprintf(_out, _max, _format, _argList);
  393. #else
  394. return ::vswprintf(_out, _max, _format, _argList);
  395. #endif // BX_COMPILER_MSVC
  396. }
  397. int32_t swnprintf(wchar_t* _out, size_t _max, const wchar_t* _format, ...)
  398. {
  399. va_list argList;
  400. va_start(argList, _format);
  401. int32_t len = vsnwprintf(_out, _max, _format, argList);
  402. va_end(argList);
  403. return len;
  404. }
  405. const char* baseName(const char* _filePath)
  406. {
  407. const char* bs = strnrchr(_filePath, '\\');
  408. const char* fs = strnrchr(_filePath, '/');
  409. const char* slash = (bs > fs ? bs : fs);
  410. const char* colon = strnrchr(_filePath, ':');
  411. const char* basename = slash > colon ? slash : colon;
  412. if (NULL != basename)
  413. {
  414. return basename+1;
  415. }
  416. return _filePath;
  417. }
  418. void prettify(char* _out, size_t _count, uint64_t _size)
  419. {
  420. uint8_t idx = 0;
  421. double size = double(_size);
  422. while (_size != (_size&0x7ff)
  423. && idx < 9)
  424. {
  425. _size >>= 10;
  426. size *= 1.0/1024.0;
  427. ++idx;
  428. }
  429. snprintf(_out, _count, "%0.2f %c%c", size, "BkMGTPEZY"[idx], idx > 0 ? 'B' : '\0');
  430. }
  431. size_t strlcpy(char* _dst, const char* _src, size_t _max)
  432. {
  433. return strlncpy(_dst, _max, _src);
  434. }
  435. size_t strlcat(char* _dst, const char* _src, size_t _max)
  436. {
  437. return strlncat(_dst, _max, _src);
  438. }
  439. } // namespace bx