string.h 8.6 KB

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