2
0

string.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. * Copyright 2010-2013 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #ifndef BX_PRINTF_H_HEADER_GUARD
  6. #define BX_PRINTF_H_HEADER_GUARD
  7. #include "bx.h"
  8. #include <alloca.h>
  9. #include <ctype.h> // tolower
  10. #include <stdarg.h> // va_list
  11. #include <stdio.h> // vsnprintf, vsnwprintf
  12. #include <string.h>
  13. #include <wchar.h> // wchar_t
  14. namespace bx
  15. {
  16. ///
  17. inline bool toBool(const char* _str)
  18. {
  19. char ch = (char)tolower(_str[0]);
  20. return ch == 't' || ch == '1';
  21. }
  22. /// Case insensitive string compare.
  23. inline int32_t stricmp(const char* _a, const char* _b)
  24. {
  25. #if BX_COMPILER_MSVC
  26. return _stricmp(_a, _b);
  27. #else
  28. return strcasecmp(_a, _b);
  29. #endif // BX_COMPILER_
  30. }
  31. ///
  32. inline size_t strnlen(const char* _str, size_t _max)
  33. {
  34. const char* end = _str + _max;
  35. const char* ptr;
  36. for (ptr = _str; ptr < end && *ptr != '\0'; ++ptr) {};
  37. return ptr - _str;
  38. }
  39. /// Find substring in string. Limit search to _size.
  40. inline const char* strnstr(const char* _str, const char* _find, size_t _size)
  41. {
  42. char first = *_find;
  43. if ('\0' == first)
  44. {
  45. return _str;
  46. }
  47. const char* cmp = _find + 1;
  48. size_t len = strlen(cmp);
  49. do
  50. {
  51. for (char match = *_str++; match != first && 0 < _size; match = *_str++, --_size)
  52. {
  53. if ('\0' == match)
  54. {
  55. return NULL;
  56. }
  57. }
  58. if (0 == _size)
  59. {
  60. return NULL;
  61. }
  62. } while (0 != strncmp(_str, cmp, len) );
  63. return --_str;
  64. }
  65. /// Find new line. Returns pointer after new line terminator.
  66. inline const char* strnl(const char* _str)
  67. {
  68. for (; '\0' != *_str; _str += strnlen(_str, 1024) )
  69. {
  70. const char* eol = strnstr(_str, "\r\n", 1024);
  71. if (NULL != eol)
  72. {
  73. return eol + 2;
  74. }
  75. eol = strnstr(_str, "\n", 1024);
  76. if (NULL != eol)
  77. {
  78. return eol + 1;
  79. }
  80. }
  81. return _str;
  82. }
  83. /// Find end of line. Retuns pointer to new line terminator.
  84. inline const char* streol(const char* _str)
  85. {
  86. for (; '\0' != *_str; _str += strnlen(_str, 1024) )
  87. {
  88. const char* eol = strnstr(_str, "\r\n", 1024);
  89. if (NULL != eol)
  90. {
  91. return eol;
  92. }
  93. eol = strnstr(_str, "\n", 1024);
  94. if (NULL != eol)
  95. {
  96. return eol;
  97. }
  98. }
  99. return _str;
  100. }
  101. /// Skip whitespace.
  102. inline const char* strws(const char* _str)
  103. {
  104. for (; isspace(*_str); ++_str) {};
  105. return _str;
  106. }
  107. /// Skip non-whitespace.
  108. inline const char* strnws(const char* _str)
  109. {
  110. for (; !isspace(*_str); ++_str) {};
  111. return _str;
  112. }
  113. /// Skip word.
  114. inline const char* strword(const char* _str)
  115. {
  116. for (char ch = *_str++; isalnum(ch) || '_' == ch; ch = *_str++) {};
  117. return _str-1;
  118. }
  119. /// Find matching block.
  120. inline const char* strmb(const char* _str, char _open, char _close)
  121. {
  122. int count = 0;
  123. for (char ch = *_str++; ch != '\0' && count >= 0; ch = *_str++)
  124. {
  125. if (ch == _open)
  126. {
  127. count++;
  128. }
  129. else if (ch == _close)
  130. {
  131. count--;
  132. if (0 == count)
  133. {
  134. return _str-1;
  135. }
  136. }
  137. }
  138. return NULL;
  139. }
  140. // Normalize string to sane line endings.
  141. inline void eolLF(char* _out, size_t _size, const char* _str)
  142. {
  143. if (0 < _size)
  144. {
  145. char* end = _out + _size - 1;
  146. for (char ch = *_str++; ch != '\0' && _out < end; ch = *_str++)
  147. {
  148. if ('\r' != ch)
  149. {
  150. *_out++ = ch;
  151. }
  152. }
  153. *_out = '\0';
  154. }
  155. }
  156. // Finds identifier.
  157. inline const char* findIdentifierMatch(const char* _str, const char* _word)
  158. {
  159. size_t len = strlen(_word);
  160. const char* ptr = strstr(_str, _word);
  161. for (; NULL != ptr; ptr = strstr(ptr + len, _word) )
  162. {
  163. if (ptr != _str)
  164. {
  165. char ch = *(ptr - 1);
  166. if (isalnum(ch) || '_' == ch)
  167. {
  168. continue;
  169. }
  170. }
  171. char ch = ptr[len];
  172. if (isalnum(ch) || '_' == ch)
  173. {
  174. continue;
  175. }
  176. return ptr;
  177. }
  178. return ptr;
  179. }
  180. // Finds any identifier from NULL terminated array of identifiers.
  181. inline const char* findIdentifierMatch(const char* _str, const char* _words[])
  182. {
  183. for (const char* word = *_words; NULL != word; ++_words, word = *_words)
  184. {
  185. const char* match = findIdentifierMatch(_str, word);
  186. if (NULL != match)
  187. {
  188. return match;
  189. }
  190. }
  191. return NULL;
  192. }
  193. /// Cross platform implementation of vsnprintf that returns number of
  194. /// characters which would have been written to the final string if
  195. /// enough space had been available.
  196. inline int32_t vsnprintf(char* _str, size_t _count, const char* _format, va_list _argList)
  197. {
  198. #if BX_COMPILER_MSVC
  199. int32_t len = ::vsnprintf_s(_str, _count, size_t(-1), _format, _argList);
  200. return -1 == len ? ::_vscprintf(_format, _argList) : len;
  201. #else
  202. return ::vsnprintf(_str, _count, _format, _argList);
  203. #endif // BX_COMPILER_MSVC
  204. }
  205. /// Cross platform implementation of vsnwprintf that returns number of
  206. /// characters which would have been written to the final string if
  207. /// enough space had been available.
  208. inline int32_t vsnwprintf(wchar_t* _str, size_t _count, const wchar_t* _format, va_list _argList)
  209. {
  210. #if BX_COMPILER_MSVC
  211. int32_t len = ::_vsnwprintf_s(_str, _count, size_t(-1), _format, _argList);
  212. return -1 == len ? ::_vscwprintf(_format, _argList) : len;
  213. #elif defined(__MINGW32__)
  214. return ::vsnwprintf(_str, _count, _format, _argList);
  215. #else
  216. return ::vswprintf(_str, _count, _format, _argList);
  217. #endif // BX_COMPILER_MSVC
  218. }
  219. ///
  220. inline int32_t snprintf(char* _str, size_t _count, const char* _format, ...) // BX_PRINTF_ARGS(3, 4)
  221. {
  222. va_list argList;
  223. va_start(argList, _format);
  224. int32_t len = vsnprintf(_str, _count, _format, argList);
  225. va_end(argList);
  226. return len;
  227. }
  228. ///
  229. inline int32_t swnprintf(wchar_t* _out, size_t _count, const wchar_t* _format, ...)
  230. {
  231. va_list argList;
  232. va_start(argList, _format);
  233. int32_t len = vsnwprintf(_out, _count, _format, argList);
  234. va_end(argList);
  235. return len;
  236. }
  237. ///
  238. template <typename Ty>
  239. inline void stringPrintfVargs(Ty& _out, const char* _format, va_list _argList)
  240. {
  241. char temp[2048];
  242. char* out = temp;
  243. int32_t len = bx::vsnprintf(out, sizeof(temp), _format, _argList);
  244. if ( (int32_t)sizeof(temp) < len)
  245. {
  246. out = (char*)alloca(len+1);
  247. len = bx::vsnprintf(out, len, _format, _argList);
  248. }
  249. out[len] = '\0';
  250. _out.append(out);
  251. }
  252. ///
  253. template <typename Ty>
  254. inline void stringPrintf(Ty& _out, const char* _format, ...)
  255. {
  256. va_list argList;
  257. va_start(argList, _format);
  258. stringPrintfVargs(_out, _format, argList);
  259. va_end(argList);
  260. }
  261. /// Extract base file name from file path.
  262. inline const char* baseName(const char* _filePath)
  263. {
  264. const char* bs = strrchr(_filePath, '\\');
  265. const char* fs = strrchr(_filePath, '/');
  266. const char* slash = (bs > fs ? bs : fs);
  267. const char* colon = strrchr(_filePath, ':');
  268. const char* basename = slash > colon ? slash : colon;
  269. if (NULL != basename)
  270. {
  271. return basename+1;
  272. }
  273. return _filePath;
  274. }
  275. /// Convert size in bytes to human readable string.
  276. inline void prettify(char* _out, size_t _count, uint64_t _size)
  277. {
  278. uint8_t idx = 0;
  279. double size = double(_size);
  280. while (_size != (_size&0x7ff)
  281. && idx < 9)
  282. {
  283. _size >>= 10;
  284. size *= 1.0/1024.0;
  285. ++idx;
  286. }
  287. snprintf(_out, _count, "%0.2f %c%c", size, "BkMGTPEZY"[idx], idx > 0 ? 'B' : '\0');
  288. }
  289. /*
  290. * Copyright (c) 1998 Todd C. Miller <[email protected]>
  291. *
  292. * Permission to use, copy, modify, and distribute this software for any
  293. * purpose with or without fee is hereby granted, provided that the above
  294. * copyright notice and this permission notice appear in all copies.
  295. *
  296. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  297. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  298. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  299. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  300. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  301. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  302. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  303. */
  304. /// Copy src to string dst of size siz. At most siz-1 characters
  305. /// will be copied. Always NUL terminates (unless siz == 0).
  306. /// Returns strlen(src); if retval >= siz, truncation occurred.
  307. inline size_t strlcpy(char* _dst, const char* _src, size_t _siz)
  308. {
  309. char* dd = _dst;
  310. const char* ss = _src;
  311. size_t nn = _siz;
  312. /* Copy as many bytes as will fit */
  313. if (nn != 0)
  314. {
  315. while (--nn != 0)
  316. {
  317. if ( (*dd++ = *ss++) == '\0')
  318. {
  319. break;
  320. }
  321. }
  322. }
  323. /* Not enough room in dst, add NUL and traverse rest of src */
  324. if (nn == 0)
  325. {
  326. if (_siz != 0)
  327. {
  328. *dd = '\0'; /* NUL-terminate dst */
  329. }
  330. while (*ss++)
  331. {
  332. }
  333. }
  334. return(ss - _src - 1); /* count does not include NUL */
  335. }
  336. /// Appends src to string dst of size siz (unlike strncat, siz is the
  337. /// full size of dst, not space left). At most siz-1 characters
  338. /// will be copied. Always NUL terminates (unless siz <= strlen(dst)).
  339. /// Returns strlen(src) + MIN(siz, strlen(initial dst)).
  340. /// If retval >= siz, truncation occurred.
  341. inline size_t strlcat(char* _dst, const char* _src, size_t _siz)
  342. {
  343. char* dd = _dst;
  344. const char *s = _src;
  345. size_t nn = _siz;
  346. size_t dlen;
  347. /* Find the end of dst and adjust bytes left but don't go past end */
  348. while (nn-- != 0 && *dd != '\0')
  349. {
  350. dd++;
  351. }
  352. dlen = dd - _dst;
  353. nn = _siz - dlen;
  354. if (nn == 0)
  355. {
  356. return(dlen + strlen(s));
  357. }
  358. while (*s != '\0')
  359. {
  360. if (nn != 1)
  361. {
  362. *dd++ = *s;
  363. nn--;
  364. }
  365. s++;
  366. }
  367. *dd = '\0';
  368. return(dlen + (s - _src)); /* count does not include NUL */
  369. }
  370. } // namespace bx
  371. #endif // BX_PRINTF_H_HEADER_GUARD