PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/Neptune/Source/Core/NptStrings.cpp

https://bitbucket.org/shawnbow/platinum
C++ | 1205 lines | 763 code | 138 blank | 304 comment | 230 complexity | d13ee2412f59c79f651e12697ffd655a MD5 | raw file
  1. /*****************************************************************
  2. |
  3. | Neptune - String Objects
  4. |
  5. | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
  6. | All rights reserved.
  7. |
  8. | Redistribution and use in source and binary forms, with or without
  9. | modification, are permitted provided that the following conditions are met:
  10. | * Redistributions of source code must retain the above copyright
  11. | notice, this list of conditions and the following disclaimer.
  12. | * Redistributions in binary form must reproduce the above copyright
  13. | notice, this list of conditions and the following disclaimer in the
  14. | documentation and/or other materials provided with the distribution.
  15. | * Neither the name of Axiomatic Systems nor the
  16. | names of its contributors may be used to endorse or promote products
  17. | derived from this software without specific prior written permission.
  18. |
  19. | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
  20. | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
  23. | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. |
  30. ****************************************************************/
  31. /*----------------------------------------------------------------------
  32. | includes
  33. +---------------------------------------------------------------------*/
  34. #include "NptConfig.h"
  35. #include "NptTypes.h"
  36. #include "NptConstants.h"
  37. #include "NptStrings.h"
  38. #include "NptResults.h"
  39. #include "NptUtils.h"
  40. #include "NptDebug.h"
  41. /*----------------------------------------------------------------------
  42. | constants
  43. +---------------------------------------------------------------------*/
  44. #define NPT_STRINGS_WHITESPACE_CHARS "\r\n\t "
  45. const unsigned int NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE = 256;
  46. const unsigned int NPT_STRING_FORMAT_BUFFER_MAX_SIZE = 0x80000; // 512k
  47. /*----------------------------------------------------------------------
  48. | helpers
  49. +---------------------------------------------------------------------*/
  50. inline char NPT_Uppercase(char x) {
  51. return (x >= 'a' && x <= 'z') ? x&0xdf : x;
  52. }
  53. inline char NPT_Lowercase(char x) {
  54. return (x >= 'A' && x <= 'Z') ? x^32 : x;
  55. }
  56. /*----------------------------------------------------------------------
  57. | NPT_String::EmptyString
  58. +---------------------------------------------------------------------*/
  59. char NPT_String::EmptyString = '\0';
  60. /*----------------------------------------------------------------------
  61. | NPT_String::FromInteger
  62. +---------------------------------------------------------------------*/
  63. NPT_String
  64. NPT_String::FromInteger(NPT_Int64 value)
  65. {
  66. char str[32];
  67. char* c = &str[31];
  68. *c-- = '\0';
  69. // handle the sign
  70. bool negative = false;
  71. if (value < 0) {
  72. negative = true;
  73. value = -value;
  74. }
  75. // process the digits
  76. do {
  77. int digit = (int)(value%10);
  78. *c-- = '0'+digit;
  79. value /= 10;
  80. } while(value);
  81. if (negative) {
  82. *c = '-';
  83. } else {
  84. ++c;
  85. }
  86. return NPT_String(c);
  87. }
  88. /*----------------------------------------------------------------------
  89. | NPT_String::FromIntegerU
  90. +---------------------------------------------------------------------*/
  91. NPT_String
  92. NPT_String::FromIntegerU(NPT_UInt64 value)
  93. {
  94. char str[32];
  95. char* c = &str[31];
  96. *c = '\0';
  97. // process the digits
  98. do {
  99. int digit = (int)(value%10);
  100. *--c = '0'+digit;
  101. value /= 10;
  102. } while(value);
  103. return NPT_String(c);
  104. }
  105. /*----------------------------------------------------------------------
  106. | NPT_String::Format
  107. +---------------------------------------------------------------------*/
  108. NPT_String
  109. NPT_String::Format(const char* format, ...)
  110. {
  111. NPT_String result;
  112. NPT_Size buffer_size = NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE; // default value
  113. va_list args;
  114. for(;;) {
  115. /* try to format (it might not fit) */
  116. result.Reserve(buffer_size);
  117. char* buffer = result.UseChars();
  118. va_start(args, format);
  119. int f_result = NPT_FormatStringVN(buffer, buffer_size, format, args);
  120. va_end(args);
  121. if (f_result >= (int)(buffer_size)) f_result = -1;
  122. if (f_result >= 0) {
  123. result.SetLength(f_result);
  124. break;
  125. }
  126. /* the buffer was too small, try something bigger */
  127. /* (we don't trust the return value of NPT_FormatStringVN */
  128. /* for the actual size needed) */
  129. buffer_size *= 2;
  130. if (buffer_size > NPT_STRING_FORMAT_BUFFER_MAX_SIZE) break;
  131. }
  132. return result;
  133. }
  134. /*----------------------------------------------------------------------
  135. | NPT_String::NPT_String
  136. +---------------------------------------------------------------------*/
  137. NPT_String::NPT_String(const char* str)
  138. {
  139. if (str == NULL) {
  140. m_Chars = NULL;
  141. } else {
  142. m_Chars = Buffer::Create(str);
  143. }
  144. }
  145. /*----------------------------------------------------------------------
  146. | NPT_String::NPT_String
  147. +---------------------------------------------------------------------*/
  148. NPT_String::NPT_String(const char* str, NPT_Size length)
  149. {
  150. if (str == NULL || length == 0) {
  151. m_Chars = NULL;
  152. } else {
  153. for (unsigned int i=0; i<length-1; i++) {
  154. if (str[i] == '\0') {
  155. if (i == 0) {
  156. m_Chars = NULL;
  157. return;
  158. }
  159. length = i;
  160. break;
  161. }
  162. }
  163. m_Chars = Buffer::Create(str, length);
  164. }
  165. }
  166. /*----------------------------------------------------------------------
  167. | NPT_String::NPT_String
  168. +---------------------------------------------------------------------*/
  169. NPT_String::NPT_String(const NPT_String& str)
  170. {
  171. if (str.GetLength() == 0) {
  172. m_Chars = NULL;
  173. } else {
  174. m_Chars = Buffer::Create(str.GetChars(), str.GetLength());
  175. }
  176. }
  177. /*----------------------------------------------------------------------
  178. | NPT_String::NPT_String
  179. +---------------------------------------------------------------------*/
  180. NPT_String::NPT_String(char c, NPT_Cardinal repeat)
  181. {
  182. if (repeat != 0) {
  183. m_Chars = Buffer::Create(c, repeat);
  184. } else {
  185. m_Chars = NULL;
  186. }
  187. }
  188. /*----------------------------------------------------------------------
  189. | NPT_String::SetLength
  190. +---------------------------------------------------------------------*/
  191. NPT_Result
  192. NPT_String::SetLength(NPT_Size length, bool pad)
  193. {
  194. // special case for 0
  195. if (length == 0) {
  196. Reset();
  197. return NPT_SUCCESS;
  198. }
  199. // reserve the space
  200. Reserve(length);
  201. // pad with spaces if necessary
  202. char* chars = UseChars();
  203. if (pad) {
  204. unsigned int current_length = GetLength();
  205. if (length > current_length) {
  206. unsigned int pad_length = length-current_length;
  207. NPT_SetMemory(chars+current_length, ' ', pad_length);
  208. }
  209. }
  210. // update the length and terminate the buffer
  211. GetBuffer()->SetLength(length);
  212. chars[length] = '\0';
  213. return NPT_SUCCESS;
  214. }
  215. /*----------------------------------------------------------------------
  216. | NPT_String::PrepareToWrite
  217. +---------------------------------------------------------------------*/
  218. inline char*
  219. NPT_String::PrepareToWrite(NPT_Size length)
  220. {
  221. NPT_ASSERT(length != 0);
  222. if (m_Chars == NULL || GetBuffer()->GetAllocated() < length) {
  223. // the buffer is too small, we need to allocate a new one.
  224. NPT_Size needed = length;
  225. if (m_Chars != NULL) {
  226. NPT_Size grow = GetBuffer()->GetAllocated()*2;
  227. if (grow > length) needed = grow;
  228. delete GetBuffer();
  229. }
  230. m_Chars = Buffer::Create(needed);
  231. }
  232. GetBuffer()->SetLength(length);
  233. return m_Chars;
  234. }
  235. /*----------------------------------------------------------------------
  236. | NPT_String::Reserve
  237. +---------------------------------------------------------------------*/
  238. void
  239. NPT_String::Reserve(NPT_Size allocate)
  240. {
  241. if (m_Chars == NULL || GetBuffer()->GetAllocated() < allocate) {
  242. // the buffer is too small, we need to allocate a new one.
  243. NPT_Size needed = allocate;
  244. if (m_Chars != NULL) {
  245. NPT_Size grow = GetBuffer()->GetAllocated()*2;
  246. if (grow > allocate) needed = grow;
  247. }
  248. NPT_Size length = GetLength();
  249. char* copy = Buffer::Create(needed, length);
  250. if (m_Chars != NULL) {
  251. CopyString(copy, m_Chars);
  252. delete GetBuffer();
  253. } else {
  254. copy[0] = '\0';
  255. }
  256. m_Chars = copy;
  257. }
  258. }
  259. /*----------------------------------------------------------------------
  260. | NPT_String::Assign
  261. +---------------------------------------------------------------------*/
  262. void
  263. NPT_String::Assign(const char* str, NPT_Size length)
  264. {
  265. if (str == NULL || length == 0) {
  266. Reset();
  267. } else {
  268. for (unsigned int i=0; i<length-1; i++) {
  269. if (str[i] == '\0') {
  270. if (i == 0) {
  271. Reset();
  272. return;
  273. } else {
  274. length = i;
  275. break;
  276. }
  277. }
  278. }
  279. PrepareToWrite(length);
  280. CopyBuffer(m_Chars, str, length);
  281. m_Chars[length] = '\0';
  282. }
  283. }
  284. /*----------------------------------------------------------------------
  285. | NPT_String::operator=
  286. +---------------------------------------------------------------------*/
  287. NPT_String&
  288. NPT_String::operator=(const char* str)
  289. {
  290. if (str == NULL) {
  291. Reset();
  292. } else {
  293. NPT_Size length = StringLength(str);
  294. if (length == 0) {
  295. Reset();
  296. } else {
  297. CopyString(PrepareToWrite(length), str);
  298. }
  299. }
  300. return *this;
  301. }
  302. /*----------------------------------------------------------------------
  303. | NPT_String::operator=
  304. +---------------------------------------------------------------------*/
  305. NPT_String&
  306. NPT_String::operator=(const NPT_String& str)
  307. {
  308. // do nothing if we're assigning to ourselves
  309. if (this != &str) {
  310. Assign(str.GetChars(), str.GetLength());
  311. }
  312. return *this;
  313. }
  314. /*----------------------------------------------------------------------
  315. | NPT_String::GetHash32
  316. +---------------------------------------------------------------------*/
  317. NPT_UInt32
  318. NPT_String::GetHash32() const
  319. {
  320. return NPT_Fnv1aHashStr32(GetChars());
  321. }
  322. /*----------------------------------------------------------------------
  323. | NPT_String::GetHash64
  324. +---------------------------------------------------------------------*/
  325. NPT_UInt64
  326. NPT_String::GetHash64() const
  327. {
  328. return NPT_Fnv1aHashStr64(GetChars());
  329. }
  330. /*----------------------------------------------------------------------
  331. | NPT_String::Append
  332. +---------------------------------------------------------------------*/
  333. void
  334. NPT_String::Append(const char* str, NPT_Size length)
  335. {
  336. // shortcut
  337. if (str == NULL || length == 0) return;
  338. // compute the new length
  339. NPT_Size old_length = GetLength();
  340. NPT_Size new_length = old_length + length;
  341. // allocate enough space
  342. Reserve(new_length);
  343. // append the new string at the end of the current one
  344. CopyBuffer(m_Chars+old_length, str, length);
  345. m_Chars[new_length] = '\0';
  346. // update the length
  347. GetBuffer()->SetLength(new_length);
  348. }
  349. /*----------------------------------------------------------------------
  350. | NPT_String::Compare
  351. +---------------------------------------------------------------------*/
  352. int
  353. NPT_String::Compare(const char *s, bool ignore_case) const
  354. {
  355. return NPT_String::Compare(GetChars(), s, ignore_case);
  356. }
  357. /*----------------------------------------------------------------------
  358. | NPT_String::Compare
  359. +---------------------------------------------------------------------*/
  360. int
  361. NPT_String::Compare(const char *s1, const char *s2, bool ignore_case)
  362. {
  363. const char *r1 = s1;
  364. const char *r2 = s2;
  365. if (ignore_case) {
  366. while (NPT_Uppercase(*r1) == NPT_Uppercase(*r2)) {
  367. if (*r1++ == '\0') {
  368. return 0;
  369. }
  370. r2++;
  371. }
  372. return NPT_Uppercase(*r1) - NPT_Uppercase(*r2);
  373. } else {
  374. while (*r1 == *r2) {
  375. if (*r1++ == '\0') {
  376. return 0;
  377. }
  378. r2++;
  379. }
  380. return (*r1 - *r2);
  381. }
  382. }
  383. /*----------------------------------------------------------------------
  384. | NPT_String::CompareN
  385. +---------------------------------------------------------------------*/
  386. int
  387. NPT_String::CompareN(const char *s, NPT_Size count, bool ignore_case) const
  388. {
  389. return NPT_String::CompareN(GetChars(), s, count, ignore_case);
  390. }
  391. /*----------------------------------------------------------------------
  392. | NPT_String::CompareN
  393. +---------------------------------------------------------------------*/
  394. int
  395. NPT_String::CompareN(const char* s1, const char *s2, NPT_Size count, bool ignore_case)
  396. {
  397. const char* me = s1;
  398. if (ignore_case) {
  399. for (unsigned int i=0; i<count; i++) {
  400. if (NPT_Uppercase(me[i]) != NPT_Uppercase(s2[i])) {
  401. return NPT_Uppercase(me[i]) - NPT_Uppercase(s2[i]);
  402. }
  403. }
  404. return 0;
  405. } else {
  406. for (unsigned int i=0; i<count; i++) {
  407. if (me[i] != s2[i]) {
  408. return (me[i] - s2[i]);
  409. }
  410. }
  411. return 0;
  412. }
  413. }
  414. /*----------------------------------------------------------------------
  415. | NPT_String::Split
  416. +---------------------------------------------------------------------*/
  417. NPT_List<NPT_String>
  418. NPT_String::Split(const char* separator) const
  419. {
  420. NPT_List<NPT_String> result;
  421. NPT_Size separator_length = NPT_StringLength(separator);
  422. // sepcial case for empty separators
  423. if (separator_length == 0) {
  424. result.Add(*this);
  425. return result;
  426. }
  427. int current = 0;
  428. int next;
  429. do {
  430. next = Find(separator, current);
  431. unsigned int end = (next>=0?(unsigned int)next:GetLength());
  432. result.Add(SubString(current, end-current));
  433. current = next+separator_length;
  434. } while (next >= 0);
  435. return result;
  436. }
  437. /*----------------------------------------------------------------------
  438. | NPT_String::SplitAny
  439. +---------------------------------------------------------------------*/
  440. NPT_Array<NPT_String>
  441. NPT_String::SplitAny(const char* separator) const
  442. {
  443. NPT_Array<NPT_String> result((GetLength()>>1)+1);
  444. // sepcial case for empty separators
  445. if (NPT_StringLength(separator) == 0) {
  446. result.Add(*this);
  447. return result;
  448. }
  449. int current = 0;
  450. int next;
  451. do {
  452. next = FindAny(separator, current);
  453. unsigned int end = (next>=0?(unsigned int)next:GetLength());
  454. result.Add(SubString(current, end-current));
  455. current = next+1;
  456. } while (next >= 0);
  457. return result;
  458. }
  459. /*----------------------------------------------------------------------
  460. | NPT_String::Join
  461. +---------------------------------------------------------------------*/
  462. NPT_String
  463. NPT_String::Join(NPT_List<NPT_String>& args, const char* separator)
  464. {
  465. NPT_String output;
  466. NPT_List<NPT_String>::Iterator arg = args.GetFirstItem();
  467. while (arg) {
  468. output += *arg;
  469. if (++arg) output += separator;
  470. }
  471. return output;
  472. }
  473. /*----------------------------------------------------------------------
  474. | NPT_String::SubString
  475. +---------------------------------------------------------------------*/
  476. NPT_String
  477. NPT_String::SubString(NPT_Ordinal first, NPT_Size length) const
  478. {
  479. if (first >= GetLength()) {
  480. first = GetLength();
  481. length = 0;
  482. } else if (first+length >= GetLength()) {
  483. length = GetLength()-first;
  484. }
  485. return NPT_String(GetChars()+first, length);
  486. }
  487. /*----------------------------------------------------------------------
  488. | NPT_StringStartsWith
  489. |
  490. | returns:
  491. | 1 if str starts with sub,
  492. | 0 if str is large enough but does not start with sub
  493. | -1 if str is too short to start with sub
  494. +---------------------------------------------------------------------*/
  495. static inline int
  496. NPT_StringStartsWith(const char* str, const char* sub, bool ignore_case)
  497. {
  498. if (ignore_case) {
  499. while (NPT_Uppercase(*str) == NPT_Uppercase(*sub)) {
  500. if (*str++ == '\0') {
  501. return 1;
  502. }
  503. sub++;
  504. }
  505. } else {
  506. while (*str == *sub) {
  507. if (*str++ == '\0') {
  508. return 1;
  509. }
  510. sub++;
  511. }
  512. }
  513. return (*sub == '\0') ? 1 : (*str == '\0' ? -1 : 0);
  514. }
  515. /*----------------------------------------------------------------------
  516. | NPT_String::StartsWith
  517. +---------------------------------------------------------------------*/
  518. bool
  519. NPT_String::StartsWith(const char *s, bool ignore_case) const
  520. {
  521. if (s == NULL) return false;
  522. return NPT_StringStartsWith(GetChars(), s, ignore_case) == 1;
  523. }
  524. /*----------------------------------------------------------------------
  525. | NPT_String::EndsWith
  526. +---------------------------------------------------------------------*/
  527. bool
  528. NPT_String::EndsWith(const char *s, bool ignore_case) const
  529. {
  530. if (s == NULL) return false;
  531. NPT_Size str_length = NPT_StringLength(s);
  532. if (str_length > GetLength()) return false;
  533. return NPT_StringStartsWith(GetChars()+GetLength()-str_length, s, ignore_case) == 1;
  534. }
  535. /*----------------------------------------------------------------------
  536. | NPT_String::Find
  537. +---------------------------------------------------------------------*/
  538. int
  539. NPT_String::Find(const char* str, NPT_Ordinal start, bool ignore_case) const
  540. {
  541. // check args
  542. if (str == NULL || start >= GetLength()) return -1;
  543. // skip to start position
  544. const char* src = m_Chars + start;
  545. // look for a substring
  546. while (*src) {
  547. int cmp = NPT_StringStartsWith(src, str, ignore_case);
  548. switch (cmp) {
  549. case -1:
  550. // ref is too short, abort
  551. return -1;
  552. case 1:
  553. // match
  554. return (int)(src-m_Chars);
  555. }
  556. src++;
  557. }
  558. return -1;
  559. }
  560. /*----------------------------------------------------------------------
  561. | NPT_String::Find
  562. +---------------------------------------------------------------------*/
  563. int
  564. NPT_String::Find(char c, NPT_Ordinal start, bool ignore_case) const
  565. {
  566. // check args
  567. if (start >= GetLength()) return -1;
  568. // skip to start position
  569. const char* src = m_Chars + start;
  570. // look for the character
  571. if (ignore_case) {
  572. while (*src) {
  573. if (NPT_Uppercase(*src) == NPT_Uppercase(c)) {
  574. return (int)(src-m_Chars);
  575. }
  576. src++;
  577. }
  578. } else {
  579. while (*src) {
  580. if (*src == c) return (int)(src-m_Chars);
  581. src++;
  582. }
  583. }
  584. return -1;
  585. }
  586. /*----------------------------------------------------------------------
  587. | NPT_String::FindAny
  588. +---------------------------------------------------------------------*/
  589. int
  590. NPT_String::FindAny(const char* s, NPT_Ordinal start, bool ignore_case) const
  591. {
  592. // check args
  593. if (start >= GetLength()) return -1;
  594. // skip to start position
  595. const char* src = m_Chars + start;
  596. // look for the character
  597. if (ignore_case) {
  598. while (*src) {
  599. for (NPT_Size i=0; i<NPT_StringLength(s); i++) {
  600. if (NPT_Uppercase(*src) == NPT_Uppercase(s[i])) {
  601. return (int)(src-m_Chars);
  602. }
  603. }
  604. src++;
  605. }
  606. } else {
  607. while (*src) {
  608. for (NPT_Size i=0; i<NPT_StringLength(s); i++) {
  609. if (*src == s[i]) return (int)(src-m_Chars);
  610. }
  611. src++;
  612. }
  613. }
  614. return -1;
  615. }
  616. /*----------------------------------------------------------------------
  617. | NPT_String::ReverseFind
  618. +---------------------------------------------------------------------*/
  619. int
  620. NPT_String::ReverseFind(const char* str, NPT_Ordinal start, bool ignore_case) const
  621. {
  622. // check args
  623. if (str == NULL || *str == '\0') return -1;
  624. // look for a substring
  625. NPT_Size my_length = GetLength();
  626. NPT_Size str_length = NPT_StringLength(str);
  627. int i=my_length-start-str_length;
  628. const char* src = GetChars();
  629. if (i<0) return -1;
  630. for (;i>=0; i--) {
  631. int cmp = NPT_StringStartsWith(src+i, str, ignore_case);
  632. if (cmp == 1) {
  633. // match
  634. return i;
  635. }
  636. }
  637. return -1;
  638. }
  639. /*----------------------------------------------------------------------
  640. | NPT_String::ReverseFind
  641. +---------------------------------------------------------------------*/
  642. int
  643. NPT_String::ReverseFind(char c, NPT_Ordinal start, bool ignore_case) const
  644. {
  645. // check args
  646. NPT_Size length = GetLength();
  647. int i = length-start-1;
  648. if (i < 0) return -1;
  649. // look for the character
  650. const char* src = GetChars();
  651. if (ignore_case) {
  652. for (;i>=0;i--) {
  653. if (NPT_Uppercase(src[i]) == NPT_Uppercase(c)) {
  654. return i;
  655. }
  656. }
  657. } else {
  658. for (;i>=0;i--) {
  659. if (src[i] == c) return i;
  660. }
  661. }
  662. return -1;
  663. }
  664. /*----------------------------------------------------------------------
  665. | NPT_String::MakeLowercase
  666. +---------------------------------------------------------------------*/
  667. void
  668. NPT_String::MakeLowercase()
  669. {
  670. // the source is the current buffer
  671. const char* src = GetChars();
  672. // convert all the characters of the existing buffer
  673. char* dst = const_cast<char*>(src);
  674. while (*dst != '\0') {
  675. *dst = NPT_Lowercase(*dst);
  676. dst++;
  677. }
  678. }
  679. /*----------------------------------------------------------------------
  680. | NPT_String::MakeUppercase
  681. +---------------------------------------------------------------------*/
  682. void
  683. NPT_String::MakeUppercase()
  684. {
  685. // the source is the current buffer
  686. const char* src = GetChars();
  687. // convert all the characters of the existing buffer
  688. char* dst = const_cast<char*>(src);
  689. while (*dst != '\0') {
  690. *dst = NPT_Uppercase(*dst);
  691. dst++;
  692. }
  693. }
  694. /*----------------------------------------------------------------------
  695. | NPT_String::ToLowercase
  696. +---------------------------------------------------------------------*/
  697. NPT_String
  698. NPT_String::ToLowercase() const
  699. {
  700. NPT_String result(*this);
  701. result.MakeLowercase();
  702. return result;
  703. }
  704. /*----------------------------------------------------------------------
  705. | NPT_String::ToUppercase
  706. +---------------------------------------------------------------------*/
  707. NPT_String
  708. NPT_String::ToUppercase() const
  709. {
  710. NPT_String result(*this);
  711. result.MakeUppercase();
  712. return result;
  713. }
  714. /*----------------------------------------------------------------------
  715. | NPT_String::Replace
  716. +---------------------------------------------------------------------*/
  717. const NPT_String&
  718. NPT_String::Replace(char a, char b)
  719. {
  720. // check args
  721. if (m_Chars == NULL || a == '\0' || b == '\0') return *this;
  722. // we are going to modify the characters
  723. char* src = m_Chars;
  724. // process the buffer in place
  725. while (*src) {
  726. if (*src == a) *src = b;
  727. src++;
  728. }
  729. return *this;
  730. }
  731. /*----------------------------------------------------------------------
  732. | NPT_String::Replace
  733. +---------------------------------------------------------------------*/
  734. const NPT_String&
  735. NPT_String::Replace(char a, const char* str)
  736. {
  737. // check args
  738. if (m_Chars == NULL || a == '\0' || str == NULL || str[0] == '\0') return *this;
  739. // optimization
  740. if (NPT_StringLength(str) == 1) return Replace(a, str[0]);
  741. // we are going to create a new string
  742. NPT_String dst;
  743. char* src = m_Chars;
  744. // reserve at least as much as input
  745. dst.Reserve(GetLength());
  746. // process the buffer
  747. while (*src) {
  748. if (*src == a) {
  749. dst += str;
  750. } else {
  751. dst += *src;
  752. }
  753. src++;
  754. }
  755. Assign(dst.GetChars(), dst.GetLength());
  756. return *this;
  757. }
  758. /*----------------------------------------------------------------------
  759. | NPT_String::Replace
  760. +---------------------------------------------------------------------*/
  761. const NPT_String&
  762. NPT_String::Replace(const char* before, const char* after)
  763. {
  764. NPT_Size size_before = NPT_StringLength(before);
  765. NPT_Size size_after = NPT_StringLength(after);
  766. int index = Find(before);
  767. while (index != NPT_STRING_SEARCH_FAILED) {
  768. Erase(index, size_before);
  769. Insert(after, index);
  770. index = Find(before, index+size_after);
  771. }
  772. return *this;
  773. }
  774. /*----------------------------------------------------------------------
  775. | NPT_String::Insert
  776. +---------------------------------------------------------------------*/
  777. const NPT_String&
  778. NPT_String::Insert(const char* str, NPT_Ordinal where)
  779. {
  780. // check args
  781. if (str == NULL || where > GetLength()) return *this;
  782. // measure the string to insert
  783. NPT_Size str_length = StringLength(str);
  784. if (str_length == 0) return *this;
  785. // compute the size of the new string
  786. NPT_Size old_length = GetLength();
  787. NPT_Size new_length = str_length + GetLength();
  788. // prepare to write the new string
  789. char* src = m_Chars;
  790. char* nst = Buffer::Create(new_length, new_length);
  791. char* dst = nst;
  792. // copy the beginning of the old string
  793. if (where > 0) {
  794. CopyBuffer(dst, src, where);
  795. src += where;
  796. dst += where;
  797. }
  798. // copy the inserted string
  799. CopyString(dst, str);
  800. dst += str_length;
  801. // copy the end of the old string
  802. if (old_length > where) {
  803. CopyString(dst, src);
  804. }
  805. // use the new string
  806. if (m_Chars) delete GetBuffer();
  807. m_Chars = nst;
  808. return *this;
  809. }
  810. /*----------------------------------------------------------------------
  811. | NPT_String::Erase
  812. +---------------------------------------------------------------------*/
  813. const NPT_String&
  814. NPT_String::Erase(NPT_Ordinal start, NPT_Cardinal count /* = 1 */)
  815. {
  816. // check bounds
  817. NPT_Size length = GetLength();
  818. if (start+count > length) {
  819. if (start >= length) return *this;
  820. count = length-start;
  821. }
  822. if (count == 0) return *this;
  823. CopyString(m_Chars+start, m_Chars+start+count);
  824. GetBuffer()->SetLength(length-count);
  825. return *this;
  826. }
  827. /*----------------------------------------------------------------------
  828. | NPT_String::ToInteger
  829. +---------------------------------------------------------------------*/
  830. NPT_Result
  831. NPT_String::ToInteger(int& value, bool relaxed) const
  832. {
  833. return NPT_ParseInteger(GetChars(), value, relaxed);
  834. }
  835. /*----------------------------------------------------------------------
  836. | NPT_String::ToInteger
  837. +---------------------------------------------------------------------*/
  838. NPT_Result
  839. NPT_String::ToInteger(unsigned int& value, bool relaxed) const
  840. {
  841. return NPT_ParseInteger(GetChars(), value, relaxed);
  842. }
  843. /*----------------------------------------------------------------------
  844. | NPT_String::ToInteger
  845. +---------------------------------------------------------------------*/
  846. NPT_Result
  847. NPT_String::ToInteger(long& value, bool relaxed) const
  848. {
  849. return NPT_ParseInteger(GetChars(), value, relaxed);
  850. }
  851. /*----------------------------------------------------------------------
  852. | NPT_String::ToInteger
  853. +---------------------------------------------------------------------*/
  854. NPT_Result
  855. NPT_String::ToInteger(unsigned long& value, bool relaxed) const
  856. {
  857. return NPT_ParseInteger(GetChars(), value, relaxed);
  858. }
  859. /*----------------------------------------------------------------------
  860. | NPT_String::ToInteger32
  861. +---------------------------------------------------------------------*/
  862. NPT_Result
  863. NPT_String::ToInteger32(NPT_Int32& value, bool relaxed) const
  864. {
  865. return NPT_ParseInteger32(GetChars(), value, relaxed);
  866. }
  867. /*----------------------------------------------------------------------
  868. | NPT_String::ToInteger32
  869. +---------------------------------------------------------------------*/
  870. NPT_Result
  871. NPT_String::ToInteger32(NPT_UInt32& value, bool relaxed) const
  872. {
  873. return NPT_ParseInteger32(GetChars(), value, relaxed);
  874. }
  875. /*----------------------------------------------------------------------
  876. | NPT_String::ToInteger64
  877. +---------------------------------------------------------------------*/
  878. NPT_Result
  879. NPT_String::ToInteger64(NPT_Int64& value, bool relaxed) const
  880. {
  881. return NPT_ParseInteger64(GetChars(), value, relaxed);
  882. }
  883. /*----------------------------------------------------------------------
  884. | NPT_String::ToInteger64
  885. +---------------------------------------------------------------------*/
  886. NPT_Result
  887. NPT_String::ToInteger64(NPT_UInt64& value, bool relaxed) const
  888. {
  889. return NPT_ParseInteger64(GetChars(), value, relaxed);
  890. }
  891. /*----------------------------------------------------------------------
  892. | NPT_String::ToFloat
  893. +---------------------------------------------------------------------*/
  894. NPT_Result
  895. NPT_String::ToFloat(float& value, bool relaxed) const
  896. {
  897. return NPT_ParseFloat(GetChars(), value, relaxed);
  898. }
  899. /*----------------------------------------------------------------------
  900. | NPT_String::TrimLeft
  901. +---------------------------------------------------------------------*/
  902. const NPT_String&
  903. NPT_String::TrimLeft()
  904. {
  905. return TrimLeft(NPT_STRINGS_WHITESPACE_CHARS);
  906. }
  907. /*----------------------------------------------------------------------
  908. | NPT_String::TrimLeft
  909. +---------------------------------------------------------------------*/
  910. const NPT_String&
  911. NPT_String::TrimLeft(char c)
  912. {
  913. char s[2] = {c, 0};
  914. return TrimLeft((const char*)s);
  915. }
  916. /*----------------------------------------------------------------------
  917. | NPT_String::TrimLeft
  918. +---------------------------------------------------------------------*/
  919. const NPT_String&
  920. NPT_String::TrimLeft(const char* chars)
  921. {
  922. if (m_Chars == NULL) return *this;
  923. const char* s = m_Chars;
  924. while (char c = *s) {
  925. const char* x = chars;
  926. while (*x) {
  927. if (*x == c) break;
  928. x++;
  929. }
  930. if (*x == 0) break; // not found
  931. s++;
  932. }
  933. if (s == m_Chars) {
  934. // nothing was trimmed
  935. return *this;
  936. }
  937. // shift chars to the left
  938. char* d = m_Chars;
  939. GetBuffer()->SetLength(GetLength()-(s-d));
  940. while ((*d++ = *s++)) {};
  941. return *this;
  942. }
  943. /*----------------------------------------------------------------------
  944. | NPT_String::TrimRight
  945. +---------------------------------------------------------------------*/
  946. const NPT_String&
  947. NPT_String::TrimRight()
  948. {
  949. return TrimRight(NPT_STRINGS_WHITESPACE_CHARS);
  950. }
  951. /*----------------------------------------------------------------------
  952. | NPT_String::TrimRight
  953. +---------------------------------------------------------------------*/
  954. const NPT_String&
  955. NPT_String::TrimRight(char c)
  956. {
  957. char s[2] = {c, 0};
  958. return TrimRight((const char*)s);
  959. }
  960. /*----------------------------------------------------------------------
  961. | NPT_String::TrimRight
  962. +---------------------------------------------------------------------*/
  963. const NPT_String&
  964. NPT_String::TrimRight(const char* chars)
  965. {
  966. if (m_Chars == NULL || m_Chars[0] == '\0') return *this;
  967. char* tail = m_Chars+GetLength()-1;
  968. char* s = tail;
  969. while (s != m_Chars-1) {
  970. const char* x = chars;
  971. while (*x) {
  972. if (*x == *s) {
  973. *s = '\0';
  974. break;
  975. }
  976. x++;
  977. }
  978. if (*x == 0) break; // not found
  979. s--;
  980. }
  981. if (s == tail) {
  982. // nothing was trimmed
  983. return *this;
  984. }
  985. GetBuffer()->SetLength(1+(int)(s-m_Chars));
  986. return *this;
  987. }
  988. /*----------------------------------------------------------------------
  989. | NPT_String::Trim
  990. +---------------------------------------------------------------------*/
  991. const NPT_String&
  992. NPT_String::Trim()
  993. {
  994. TrimLeft();
  995. return TrimRight();
  996. }
  997. /*----------------------------------------------------------------------
  998. | NPT_String::Trim
  999. +---------------------------------------------------------------------*/
  1000. const NPT_String&
  1001. NPT_String::Trim(char c)
  1002. {
  1003. char s[2] = {c, 0};
  1004. TrimLeft((const char*)s);
  1005. return TrimRight((const char*)s);
  1006. }
  1007. /*----------------------------------------------------------------------
  1008. | NPT_String::Trim
  1009. +---------------------------------------------------------------------*/
  1010. const NPT_String&
  1011. NPT_String::Trim(const char* chars)
  1012. {
  1013. TrimLeft(chars);
  1014. return TrimRight(chars);
  1015. }
  1016. /*----------------------------------------------------------------------
  1017. | NPT_String::operator+(const NPT_String&, const char*)
  1018. +---------------------------------------------------------------------*/
  1019. NPT_String
  1020. operator+(const NPT_String& s1, const char* s2)
  1021. {
  1022. // shortcut
  1023. if (s2 == NULL) return NPT_String(s1);
  1024. // measure strings
  1025. NPT_Size s1_length = s1.GetLength();
  1026. NPT_Size s2_length = NPT_String::StringLength(s2);
  1027. // allocate space for the new string
  1028. NPT_String result;
  1029. char* start = result.PrepareToWrite(s1_length+s2_length);
  1030. // concatenate the two strings into the result
  1031. NPT_String::CopyBuffer(start, s1, s1_length);
  1032. NPT_String::CopyString(start+s1_length, s2);
  1033. return result;
  1034. }
  1035. /*----------------------------------------------------------------------
  1036. | NPT_String::operator+(const NPT_String& , const char*)
  1037. +---------------------------------------------------------------------*/
  1038. NPT_String
  1039. operator+(const char* s1, const NPT_String& s2)
  1040. {
  1041. // shortcut
  1042. if (s1 == NULL) return NPT_String(s2);
  1043. // measure strings
  1044. NPT_Size s1_length = NPT_String::StringLength(s1);
  1045. NPT_Size s2_length = s2.GetLength();
  1046. // allocate space for the new string
  1047. NPT_String result;
  1048. char* start = result.PrepareToWrite(s1_length+s2_length);
  1049. // concatenate the two strings into the result
  1050. NPT_String::CopyBuffer(start, s1, s1_length);
  1051. NPT_String::CopyString(start+s1_length, s2.GetChars());
  1052. return result;
  1053. }
  1054. /*----------------------------------------------------------------------
  1055. | NPT_String::operator+(const NPT_String& , char)
  1056. +---------------------------------------------------------------------*/
  1057. NPT_String
  1058. operator+(const NPT_String& s1, char c)
  1059. {
  1060. // allocate space for the new string
  1061. NPT_String result;
  1062. result.Reserve(s1.GetLength()+1);
  1063. // append
  1064. result = s1;
  1065. result += c;
  1066. return result;
  1067. }