StrLib.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. // This code is in the public domain -- Ignacio Castaño <[email protected]>
  2. #include "StrLib.h"
  3. #include "Memory.h"
  4. #include "Utils.h" // swap
  5. #include <math.h> // log
  6. #include <stdio.h> // vsnprintf
  7. #include <string.h> // strlen, strcmp, etc.
  8. #if NV_CC_MSVC
  9. #include <stdarg.h> // vsnprintf
  10. #endif
  11. using namespace nv;
  12. namespace
  13. {
  14. static char * strAlloc(uint size)
  15. {
  16. return malloc<char>(size);
  17. }
  18. static char * strReAlloc(char * str, uint size)
  19. {
  20. return realloc<char>(str, size);
  21. }
  22. static void strFree(const char * str)
  23. {
  24. return free<char>(str);
  25. }
  26. /*static char * strDup( const char * str )
  27. {
  28. nvDebugCheck( str != NULL );
  29. uint len = uint(strlen( str ) + 1);
  30. char * dup = strAlloc( len );
  31. memcpy( dup, str, len );
  32. return dup;
  33. }*/
  34. // helper function for integer to string conversion.
  35. static char * i2a( uint i, char *a, uint r )
  36. {
  37. if( i / r > 0 ) {
  38. a = i2a( i / r, a, r );
  39. }
  40. *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % r];
  41. return a + 1;
  42. }
  43. // Locale independent functions.
  44. static inline char toUpper( char c ) {
  45. return (c<'a' || c>'z') ? (c) : (c+'A'-'a');
  46. }
  47. static inline char toLower( char c ) {
  48. return (c<'A' || c>'Z') ? (c) : (c+'a'-'A');
  49. }
  50. static inline bool isAlpha( char c ) {
  51. return (c>='a' && c<='z') || (c>='A' && c<='Z');
  52. }
  53. static inline bool isDigit( char c ) {
  54. return c>='0' && c<='9';
  55. }
  56. static inline bool isAlnum( char c ) {
  57. return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
  58. }
  59. }
  60. uint nv::strLen(const char * str)
  61. {
  62. nvDebugCheck(str != NULL);
  63. return toU32(strlen(str));
  64. }
  65. int nv::strCmp(const char * s1, const char * s2)
  66. {
  67. nvDebugCheck(s1 != NULL);
  68. nvDebugCheck(s2 != NULL);
  69. return strcmp(s1, s2);
  70. }
  71. int nv::strCaseCmp(const char * s1, const char * s2)
  72. {
  73. nvDebugCheck(s1 != NULL);
  74. nvDebugCheck(s1 != NULL);
  75. #if NV_CC_MSVC
  76. return _stricmp(s1, s2);
  77. #else
  78. return strcasecmp(s1, s2);
  79. #endif
  80. }
  81. bool nv::strEqual(const char * s1, const char * s2)
  82. {
  83. if (s1 == s2) return true;
  84. if (s1 == NULL || s2 == NULL) return false;
  85. return strCmp(s1, s2) == 0;
  86. }
  87. bool nv::strCaseEqual(const char * s1, const char * s2)
  88. {
  89. if (s1 == s2) return true;
  90. if (s1 == NULL || s2 == NULL) return false;
  91. return strCaseCmp(s1, s2) == 0;
  92. }
  93. bool nv::strBeginsWith(const char * str, const char * prefix)
  94. {
  95. //return strstr(str, prefix) == dst;
  96. return strncmp(str, prefix, strlen(prefix)) == 0;
  97. }
  98. bool nv::strEndsWith(const char * str, const char * suffix)
  99. {
  100. uint ml = strLen(str);
  101. uint sl = strLen(suffix);
  102. if (ml < sl) return false;
  103. return strncmp(str + ml - sl, suffix, sl) == 0;
  104. }
  105. void nv::strCpy(char * dst, uint size, const char * src)
  106. {
  107. nvDebugCheck(dst != NULL);
  108. nvDebugCheck(src != NULL);
  109. #if NV_CC_MSVC && _MSC_VER >= 1400
  110. strcpy_s(dst, size, src);
  111. #else
  112. NV_UNUSED(size);
  113. strcpy(dst, src);
  114. #endif
  115. }
  116. void nv::strCpy(char * dst, uint size, const char * src, uint len)
  117. {
  118. nvDebugCheck(dst != NULL);
  119. nvDebugCheck(src != NULL);
  120. #if NV_CC_MSVC && _MSC_VER >= 1400
  121. strncpy_s(dst, size, src, len);
  122. #else
  123. NV_UNUSED(size);
  124. strncpy(dst, src, len);
  125. #endif
  126. }
  127. void nv::strCat(char * dst, uint size, const char * src)
  128. {
  129. nvDebugCheck(dst != NULL);
  130. nvDebugCheck(src != NULL);
  131. #if NV_CC_MSVC && _MSC_VER >= 1400
  132. strcat_s(dst, size, src);
  133. #else
  134. NV_UNUSED(size);
  135. strcat(dst, src);
  136. #endif
  137. }
  138. /** Pattern matching routine. I don't remember where did I get this. */
  139. bool nv::strMatch(const char * str, const char * pat)
  140. {
  141. nvDebugCheck(str != NULL);
  142. nvDebugCheck(pat != NULL);
  143. char c2;
  144. while (true) {
  145. if (*pat==0) {
  146. if (*str==0) return true;
  147. else return false;
  148. }
  149. if ((*str==0) && (*pat!='*')) return false;
  150. if (*pat=='*') {
  151. pat++;
  152. if (*pat==0) return true;
  153. while (true) {
  154. if (strMatch(str, pat)) return true;
  155. if (*str==0) return false;
  156. str++;
  157. }
  158. }
  159. if (*pat=='?') goto match;
  160. if (*pat=='[') {
  161. pat++;
  162. while (true) {
  163. if ((*pat==']') || (*pat==0)) return false;
  164. if (*pat==*str) break;
  165. if (pat[1] == '-') {
  166. c2 = pat[2];
  167. if (c2==0) return false;
  168. if ((*pat<=*str) && (c2>=*str)) break;
  169. if ((*pat>=*str) && (c2<=*str)) break;
  170. pat+=2;
  171. }
  172. pat++;
  173. }
  174. while (*pat!=']') {
  175. if (*pat==0) {
  176. pat--;
  177. break;
  178. }
  179. pat++;
  180. }
  181. goto match;
  182. }
  183. if (*pat == NV_PATH_SEPARATOR) {
  184. pat++;
  185. if (*pat==0) return false;
  186. }
  187. if (*pat!=*str) return false;
  188. match:
  189. pat++;
  190. str++;
  191. }
  192. }
  193. /** Empty string. */
  194. StringBuilder::StringBuilder() : m_size(0), m_str(NULL)
  195. {
  196. }
  197. /** Preallocate space. */
  198. StringBuilder::StringBuilder( uint size_hint ) : m_size(size_hint)
  199. {
  200. nvDebugCheck(m_size > 0);
  201. m_str = strAlloc(m_size);
  202. *m_str = '\0';
  203. }
  204. /** Copy ctor. */
  205. StringBuilder::StringBuilder( const StringBuilder & s ) : m_size(0), m_str(NULL)
  206. {
  207. copy(s);
  208. }
  209. /** Copy string. */
  210. StringBuilder::StringBuilder(const char * s) : m_size(0), m_str(NULL)
  211. {
  212. copy(s);
  213. }
  214. /** Copy string. */
  215. StringBuilder::StringBuilder(const char * s, uint len) : m_size(0), m_str(NULL)
  216. {
  217. copy(s, len);
  218. }
  219. /** Delete the string. */
  220. StringBuilder::~StringBuilder()
  221. {
  222. strFree(m_str);
  223. }
  224. /** Format a string safely. */
  225. StringBuilder & StringBuilder::format( const char * fmt, ... )
  226. {
  227. nvDebugCheck(fmt != NULL);
  228. va_list arg;
  229. va_start( arg, fmt );
  230. formatList( fmt, arg );
  231. va_end( arg );
  232. return *this;
  233. }
  234. /** Format a string safely. */
  235. StringBuilder & StringBuilder::formatList( const char * fmt, va_list arg )
  236. {
  237. nvDebugCheck(fmt != NULL);
  238. if (m_size == 0) {
  239. m_size = 64;
  240. m_str = strAlloc( m_size );
  241. }
  242. va_list tmp;
  243. va_copy(tmp, arg);
  244. #if NV_CC_MSVC && _MSC_VER >= 1400
  245. int n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp);
  246. #else
  247. int n = vsnprintf(m_str, m_size, fmt, tmp);
  248. #endif
  249. va_end(tmp);
  250. while( n < 0 || n >= int(m_size) ) {
  251. if( n > -1 ) {
  252. m_size = n + 1;
  253. }
  254. else {
  255. m_size *= 2;
  256. }
  257. m_str = strReAlloc(m_str, m_size);
  258. va_copy(tmp, arg);
  259. #if NV_CC_MSVC && _MSC_VER >= 1400
  260. n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp);
  261. #else
  262. n = vsnprintf(m_str, m_size, fmt, tmp);
  263. #endif
  264. va_end(tmp);
  265. }
  266. nvDebugCheck(n < int(m_size));
  267. // Make sure it's null terminated.
  268. nvDebugCheck(m_str[n] == '\0');
  269. //str[n] = '\0';
  270. return *this;
  271. }
  272. /** Append a string. */
  273. StringBuilder & StringBuilder::append( const char * s )
  274. {
  275. nvDebugCheck(s != NULL);
  276. const uint slen = uint(strlen( s ));
  277. if (m_str == NULL) {
  278. m_size = slen + 1;
  279. m_str = strAlloc(m_size);
  280. memcpy(m_str, s, m_size);
  281. }
  282. else {
  283. const uint len = uint(strlen( m_str ));
  284. if (m_size < len + slen + 1) {
  285. m_size = len + slen + 1;
  286. m_str = strReAlloc(m_str, m_size);
  287. }
  288. memcpy(m_str + len, s, slen + 1);
  289. }
  290. return *this;
  291. }
  292. /** Append a formatted string. */
  293. StringBuilder & StringBuilder::appendFormat( const char * fmt, ... )
  294. {
  295. nvDebugCheck( fmt != NULL );
  296. va_list arg;
  297. va_start( arg, fmt );
  298. appendFormatList( fmt, arg );
  299. va_end( arg );
  300. return *this;
  301. }
  302. /** Append a formatted string. */
  303. StringBuilder & StringBuilder::appendFormatList( const char * fmt, va_list arg )
  304. {
  305. nvDebugCheck( fmt != NULL );
  306. va_list tmp;
  307. va_copy(tmp, arg);
  308. if (m_size == 0) {
  309. formatList(fmt, arg);
  310. }
  311. else {
  312. StringBuilder tmp_str;
  313. tmp_str.formatList( fmt, tmp );
  314. append( tmp_str.str() );
  315. }
  316. va_end(tmp);
  317. return *this;
  318. }
  319. // Append n spaces.
  320. StringBuilder & StringBuilder::appendSpace(uint n)
  321. {
  322. if (m_str == NULL) {
  323. m_size = n + 1;
  324. m_str = strAlloc(m_size);
  325. memset(m_str, ' ', m_size);
  326. m_str[n] = '\0';
  327. }
  328. else {
  329. const uint len = strLen(m_str);
  330. if (m_size < len + n + 1) {
  331. m_size = len + n + 1;
  332. m_str = strReAlloc(m_str, m_size);
  333. }
  334. memset(m_str + len, ' ', n);
  335. m_str[len+n] = '\0';
  336. }
  337. return *this;
  338. }
  339. /** Convert number to string in the given base. */
  340. StringBuilder & StringBuilder::number( int i, int base )
  341. {
  342. nvCheck( base >= 2 );
  343. nvCheck( base <= 36 );
  344. // @@ This needs to be done correctly.
  345. // length = floor(log(i, base));
  346. uint len = uint(log(float(i)) / log(float(base)) + 2); // one more if negative
  347. reserve(len);
  348. if( i < 0 ) {
  349. *m_str = '-';
  350. *i2a(uint(-i), m_str+1, base) = 0;
  351. }
  352. else {
  353. *i2a(i, m_str, base) = 0;
  354. }
  355. return *this;
  356. }
  357. /** Convert number to string in the given base. */
  358. StringBuilder & StringBuilder::number( uint i, int base )
  359. {
  360. nvCheck( base >= 2 );
  361. nvCheck( base <= 36 );
  362. // @@ This needs to be done correctly.
  363. // length = floor(log(i, base));
  364. uint len = uint(log(float(i)) / log(float(base)) - 0.5f + 1);
  365. reserve(len);
  366. *i2a(i, m_str, base) = 0;
  367. return *this;
  368. }
  369. /** Resize the string preserving the contents. */
  370. StringBuilder & StringBuilder::reserve( uint size_hint )
  371. {
  372. nvCheck(size_hint != 0);
  373. if (size_hint > m_size) {
  374. m_str = strReAlloc(m_str, size_hint);
  375. m_size = size_hint;
  376. }
  377. return *this;
  378. }
  379. /** Copy a string safely. */
  380. StringBuilder & StringBuilder::copy(const char * s)
  381. {
  382. nvCheck( s != NULL );
  383. const uint str_size = uint(strlen( s )) + 1;
  384. reserve(str_size);
  385. memcpy(m_str, s, str_size);
  386. return *this;
  387. }
  388. /** Copy a string safely. */
  389. StringBuilder & StringBuilder::copy(const char * s, uint len)
  390. {
  391. nvCheck( s != NULL );
  392. const uint str_size = len + 1;
  393. reserve(str_size);
  394. strCpy(m_str, str_size, s, len);
  395. return *this;
  396. }
  397. /** Copy an StringBuilder. */
  398. StringBuilder & StringBuilder::copy( const StringBuilder & s )
  399. {
  400. if (s.m_str == NULL) {
  401. nvCheck( s.m_size == 0 );
  402. reset();
  403. }
  404. else {
  405. reserve( s.m_size );
  406. strCpy( m_str, s.m_size, s.m_str );
  407. }
  408. return *this;
  409. }
  410. bool StringBuilder::endsWith(const char * str) const
  411. {
  412. uint l = uint(strlen(str));
  413. uint ml = uint(strlen(m_str));
  414. if (ml < l) return false;
  415. return strncmp(m_str + ml - l, str, l) == 0;
  416. }
  417. bool StringBuilder::beginsWith(const char * str) const
  418. {
  419. size_t l = strlen(str);
  420. return strncmp(m_str, str, l) == 0;
  421. }
  422. /** Reset the string. */
  423. void StringBuilder::reset()
  424. {
  425. m_size = 0;
  426. strFree( m_str );
  427. m_str = NULL;
  428. }
  429. /** Release the allocated string. */
  430. char * StringBuilder::release()
  431. {
  432. char * str = m_str;
  433. m_size = 0;
  434. m_str = NULL;
  435. return str;
  436. }
  437. // Swap strings.
  438. void nv::swap(StringBuilder & a, StringBuilder & b) {
  439. swap(a.m_size, b.m_size);
  440. swap(a.m_str, b.m_str);
  441. }
  442. /// Get the file name from a path.
  443. const char * Path::fileName() const
  444. {
  445. return fileName(m_str);
  446. }
  447. /// Get the extension from a file path.
  448. const char * Path::extension() const
  449. {
  450. return extension(m_str);
  451. }
  452. /// Toggles path separators (ie. \\ into /).
  453. void Path::translatePath(char pathSeparator/*=NV_PATH_SEPARATOR*/)
  454. {
  455. nvCheck( m_str != NULL );
  456. for (int i = 0; ; i++) {
  457. if (m_str[i] == '\0') break;
  458. if (m_str[i] == '\\' || m_str[i] == '/') m_str[i] = pathSeparator;
  459. }
  460. }
  461. void Path::appendSeparator(char pathSeparator/*=NV_PATH_SEPARATOR*/)
  462. {
  463. nvCheck(!isNull());
  464. const uint l = length();
  465. if (m_str[l] != '\\' && m_str[l] != '/') {
  466. char separatorString[] = { pathSeparator, '\0' };
  467. append(separatorString);
  468. }
  469. }
  470. /**
  471. * Strip the file name from a path.
  472. * @warning path cannot end with '/' o '\\', can't it?
  473. */
  474. void Path::stripFileName()
  475. {
  476. nvCheck( m_str != NULL );
  477. int length = (int)strlen(m_str) - 1;
  478. while (length > 0 && m_str[length] != '/' && m_str[length] != '\\'){
  479. length--;
  480. }
  481. if( length ) {
  482. m_str[length+1] = 0;
  483. }
  484. else {
  485. m_str[0] = 0;
  486. }
  487. }
  488. /// Strip the extension from a path name.
  489. void Path::stripExtension()
  490. {
  491. nvCheck( m_str != NULL );
  492. int length = (int)strlen(m_str) - 1;
  493. while (length > 0 && m_str[length] != '.') {
  494. length--;
  495. if( m_str[length] == NV_PATH_SEPARATOR ) {
  496. return; // no extension
  497. }
  498. }
  499. if (length > 0) {
  500. m_str[length] = 0;
  501. }
  502. }
  503. /// Get the path separator.
  504. // static
  505. char Path::separator()
  506. {
  507. return NV_PATH_SEPARATOR;
  508. }
  509. // static
  510. const char * Path::fileName(const char * str)
  511. {
  512. nvCheck( str != NULL );
  513. int length = (int)strlen(str) - 1;
  514. while (length >= 0 && str[length] != '\\' && str[length] != '/') {
  515. length--;
  516. }
  517. return &str[length+1];
  518. }
  519. // static
  520. const char * Path::extension(const char * str)
  521. {
  522. nvCheck( str != NULL );
  523. int length, l;
  524. l = length = (int)strlen( str );
  525. while (length > 0 && str[length] != '.') {
  526. length--;
  527. if (str[length] == '\\' || str[length] == '/') {
  528. return &str[l]; // no extension
  529. }
  530. }
  531. if (length == 0) {
  532. return &str[l];
  533. }
  534. return &str[length];
  535. }
  536. /// Clone this string
  537. String String::clone() const
  538. {
  539. String str(data);
  540. return str;
  541. }
  542. void String::setString(const char * str)
  543. {
  544. if (str == NULL) {
  545. data = NULL;
  546. }
  547. else {
  548. allocString( str );
  549. addRef();
  550. }
  551. }
  552. void String::setString(const char * str, uint length)
  553. {
  554. nvDebugCheck(str != NULL);
  555. allocString(str, length);
  556. addRef();
  557. }
  558. void String::setString(const StringBuilder & str)
  559. {
  560. if (str.str() == NULL) {
  561. data = NULL;
  562. }
  563. else {
  564. allocString(str.str());
  565. addRef();
  566. }
  567. }
  568. // Add reference count.
  569. void String::addRef()
  570. {
  571. if (data != NULL)
  572. {
  573. setRefCount(getRefCount() + 1);
  574. }
  575. }
  576. // Decrease reference count.
  577. void String::release()
  578. {
  579. if (data != NULL)
  580. {
  581. const uint16 count = getRefCount();
  582. setRefCount(count - 1);
  583. if (count - 1 == 0) {
  584. free(data - 2);
  585. data = NULL;
  586. }
  587. }
  588. }
  589. void String::allocString(const char * str, uint len)
  590. {
  591. const char * ptr = malloc<char>(2 + len + 1);
  592. setData( ptr );
  593. setRefCount( 0 );
  594. // Copy string.
  595. strCpy(const_cast<char *>(data), len+1, str, len);
  596. // Add terminating character.
  597. const_cast<char *>(data)[len] = '\0';
  598. }
  599. void nv::swap(String & a, String & b) {
  600. swap(a.data, b.data);
  601. }