string.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. #include <bfc/wasabi_std.h>
  2. #include "string.h"
  3. #include <bfc/nsguid.h>
  4. String::String(const char *initial_val)
  5. : val(NULL)
  6. {
  7. setValue(initial_val);
  8. }
  9. String::String(const String &s)
  10. : val(NULL)
  11. {
  12. if (s == NULL) setValue(NULL);
  13. else setValue(s.getValue());
  14. }
  15. String::String(const String *s)
  16. : val(NULL)
  17. {
  18. if (s == NULL) setValue(NULL);
  19. else setValue(s->getValue());
  20. }
  21. String::~String()
  22. {
  23. FREE(val);
  24. }
  25. const char *String::getValueSafe(const char *def_val) const
  26. {
  27. if (val == NULL)
  28. return def_val;
  29. else
  30. return val;
  31. }
  32. int String::getChar(int pos, int bounds_check)
  33. {
  34. if (pos < 0 || val == NULL) return -1;
  35. if (bounds_check && pos >= len()) return -1;
  36. return val[pos];
  37. }
  38. int String::setChar(int pos, int value)
  39. {
  40. if (pos < 0 || val == NULL) return -1;
  41. return val[pos] = value;
  42. }
  43. const char *String::setValue(const char *newval)
  44. {
  45. if (newval != val)
  46. {
  47. if (newval == NULL)
  48. {
  49. FREE(val);
  50. val = NULL;
  51. }
  52. else
  53. {
  54. int len = STRLEN(newval);
  55. if (val != NULL)
  56. #ifdef STRING_REALLOC_OPTIMS
  57. {
  58. int oldlen = STRLEN(val);
  59. // if smaller but greater than half previous size, don't realloc
  60. if (len > oldlen || len < oldlen / 2)
  61. val = (char *)REALLOC(val, len + 1);
  62. }
  63. #else
  64. val = (char *)REALLOC(val, len + 1);
  65. #endif
  66. else
  67. val = (char *)MALLOC(len + 1);
  68. ASSERT(newval != NULL);
  69. MEMCPY_(val, newval, len + 1);
  70. }
  71. }
  72. return getValue();
  73. }
  74. int String::len() const
  75. {
  76. return (val == NULL) ? 0 : STRLEN(val);
  77. }
  78. int String::isempty() const
  79. {
  80. return (!val || !*val);
  81. }
  82. void String::toupper()
  83. {
  84. if (!isempty())
  85. STRTOUPPER(val);
  86. }
  87. void String::tolower()
  88. {
  89. if (!isempty())
  90. STRTOLOWER(val);
  91. }
  92. int String::isequal(const char *otherval) const
  93. {
  94. return !STRCMPSAFE(getValue(), otherval);
  95. }
  96. int String::iscaseequal(const char *otherval) const
  97. {
  98. return !STRICMPSAFE(getValue(), otherval);
  99. }
  100. int String::islessthan(const char *otherval) const
  101. {
  102. return STRCMPSAFE(getValue(), otherval) < 0;
  103. }
  104. void String::changeChar(int from, int to)
  105. {
  106. if (val == NULL) return ;
  107. int length = len();
  108. for (int i = 0; i < length; i++)
  109. if (val[i] == from) val[i] = to;
  110. }
  111. void String::truncateOnChar(int which, int fromright)
  112. {
  113. if (fromright)
  114. {
  115. if (val == NULL) return ;
  116. int length = len();
  117. for (int i = length - 1; i >= 0; i--)
  118. {
  119. if (val[i] == which)
  120. {
  121. val[i] = '\0';
  122. return ;
  123. }
  124. }
  125. }
  126. else
  127. {
  128. changeChar(which, '\0');
  129. }
  130. }
  131. int String::lastChar()
  132. {
  133. if (isempty()) return -1;
  134. return val[len() - 1];
  135. }
  136. const char *String::printf(const char *format, ...)
  137. {
  138. va_list args;
  139. va_start (args, format);
  140. va_sprintf(format, args);
  141. va_end(args);
  142. return getValue();
  143. }
  144. const char *String::cat(const char *value)
  145. {
  146. if (value == NULL || *value == 0) return getValue();
  147. if (val == NULL) return setValue(value);
  148. return catn(value, STRLEN(value));
  149. }
  150. const char *String::catn(const char *value, int len)
  151. {
  152. if (len == 0) return val;
  153. if (value == NULL || *value == 0) return getValue();
  154. if (val == NULL) return ncpy(value, len);
  155. int ol = STRLEN(val);
  156. val = (char *)REALLOC(val, ol + len + 1);
  157. val[ol + len] = 0;
  158. STRNCPY(val + ol, value, len);
  159. return val;
  160. }
  161. const char *String::prepend(const char *value)
  162. {
  163. if (value == NULL || *value == 0) return getValue();
  164. if (val == NULL) return setValue(value);
  165. StringPrintf temp("%s%s", value, getValue());
  166. swap(&temp);
  167. return getValue();
  168. }
  169. // replaces string with n chars of val or length of val, whichever is less.
  170. const char *String::ncpy(const char *newstr, int numchars)
  171. {
  172. val = (char *)REALLOC(val, numchars + 1);
  173. val[numchars] = 0;
  174. STRNCPY(val, newstr, numchars);
  175. return getValue();
  176. }
  177. void String::strncpyTo(char *dest, int maxlen)
  178. {
  179. ASSERT(dest != NULL);
  180. ASSERT(maxlen >= 0);
  181. if (maxlen == 0) return ;
  182. else if (maxlen == 1)
  183. {
  184. *dest = '\0';
  185. return ;
  186. }
  187. const char *src = val;
  188. if (src == NULL) src = "";
  189. int copylen = MIN(STRLEN(src), maxlen);
  190. if (maxlen == copylen) copylen--; // make room for 0-termination
  191. MEMCPY(dest, src, copylen);
  192. dest[copylen] = 0;
  193. }
  194. // -----------------------------------------
  195. // Character based find-n-splice methods --
  196. // "l" and "r" prefixes specify to begin at
  197. // front or back of string:
  198. #ifdef FAST_METHODS
  199. #undef FAST_METHODS
  200. #endif//FAST_METHODS
  201. #ifdef SAFE_METHODS
  202. #undef SAFE_METHODS
  203. #endif//SAFE_METHODS
  204. #ifdef USE
  205. #undef USE
  206. #endif//USE
  207. #define FAST_METHODS 1
  208. #define SAFE_METHODS 0
  209. #define USE FAST_METHODS
  210. // Returns index of first found, -1 if not found.
  211. int String::lFindChar(char findval)
  212. {
  213. int length = len();
  214. for (int i = 0; i < length; i++)
  215. {
  216. if (val[i] == findval)
  217. {
  218. return i;
  219. }
  220. }
  221. return -1;
  222. }
  223. // Same as above, save the "findval" is a string where it searches
  224. // for any of the characters in the string.
  225. int String::lFindChar(const char *findval)
  226. {
  227. int length = len();
  228. int numchars = STRLEN(findval);
  229. for (int i = 0; i < length; i++)
  230. {
  231. for (int j = 0; j < numchars; j++)
  232. {
  233. if (val[i] == findval[j])
  234. {
  235. return i;
  236. }
  237. }
  238. }
  239. return -1;
  240. }
  241. int String::rFindChar(char findval)
  242. {
  243. int length = len();
  244. for (int i = length - 1; i > 0; i--)
  245. {
  246. if (val[i] == findval)
  247. {
  248. return i;
  249. }
  250. }
  251. return -1;
  252. }
  253. // Same as above, save the "findval" is a string where it searches
  254. // for any of the characters in the string.
  255. int String::rFindChar(const char *findval)
  256. {
  257. int length = len();
  258. int numchars = STRLEN(findval);
  259. for (int i = length - 1; i > 0; i--)
  260. {
  261. for (int j = 0; j < numchars; j++)
  262. {
  263. if (val[i] == findval[j])
  264. {
  265. return i;
  266. }
  267. }
  268. }
  269. return -1;
  270. }
  271. // Splits string at findval. Characters passed by search, including the
  272. // found character, are MOVED to the returned string. If there is no char
  273. // to be found, the entire string is returnef and the called instance is
  274. // left empty. (Makes looped splits very easy).
  275. String String::lSplit(int idxval)
  276. {
  277. if (val == NULL) return String();
  278. if (idxval == -1)
  279. { // Not Found
  280. // Copy our contents to return on the stack
  281. String retval(val);
  282. // And zero the string.
  283. if (val)
  284. {
  285. val[0] = 0;
  286. }
  287. return retval;
  288. }
  289. else
  290. {
  291. String retval;
  292. // Copy into retval the number of characters to the found char index.
  293. retval.ncpy(val, idxval + 1);
  294. {
  295. String testscope;
  296. // Copy into retval the number of characters to the found char index.
  297. testscope.ncpy(val, idxval + 1);
  298. }
  299. #if USE == FAST_METHODS
  300. size_t len = strlen(val + idxval + 1);
  301. MEMCPY(val, val + idxval + 1, len + 1);
  302. #elif USE == SAFE_METHODS
  303. // Copy from the found index downwards to save for this object
  304. String temp(val + idxval + 1);
  305. // And then copy into ourselves the tempspace.
  306. *this = temp;
  307. #endif
  308. return retval;
  309. }
  310. // this will never be hit. many compilers are too stupid to realize this.
  311. return String();
  312. }
  313. String String::lSplitChar(char findval)
  314. {
  315. if (val == NULL) return String();
  316. // The index of the found character
  317. int idxval = lFindChar(findval);
  318. return lSplit(idxval);
  319. }
  320. String String::lSplitChar(const char *findval)
  321. {
  322. if (val == NULL) return String();
  323. // The index of the found character
  324. int idxval = lFindChar(findval);
  325. return lSplit(idxval);
  326. }
  327. String String::rSplit(int idxval)
  328. {
  329. if (val == NULL) return String();
  330. if (idxval == -1)
  331. { // Not Found
  332. // Copy our contents to return on the stack
  333. String retval(val);
  334. // And zero the string.
  335. val[0] = 0;
  336. return retval;
  337. }
  338. else
  339. {
  340. // Copy from the found index downwards to the retval
  341. String retval(val + idxval);
  342. // Terminate the found char index
  343. val[idxval] = 0;
  344. // That was easier, wasn't it?
  345. return retval;
  346. }
  347. // this will never be hit. many compilers are too stupid to realize this.
  348. return String();
  349. }
  350. String String::rSplitChar(char findval)
  351. {
  352. if (val == NULL) return String();
  353. // The index of the found character
  354. int idxval = rFindChar(findval);
  355. return rSplit(idxval);
  356. }
  357. String String::rSplitChar(const char *findval)
  358. {
  359. if (val == NULL) return String();
  360. // The index of the found character
  361. int idxval = rFindChar(findval);
  362. return rSplit(idxval);
  363. }
  364. // Same as split, except the find char is cut completely.
  365. String String::lSpliceChar(char findval)
  366. {
  367. if (val == NULL) return String();
  368. //CUT // Auto-scope reference allows us to avoid a copy.
  369. //CUT String & retval = lSplitChar(findval);
  370. //BU gcc doesn't agree with you and neither do I :/
  371. String retval = lSplitChar(findval);
  372. // We need to strip the findval char, which is the end char.
  373. int end = retval.len();
  374. if (end)
  375. {
  376. if (retval.val[end - 1] == findval)
  377. {
  378. retval.val[end - 1] = 0;
  379. }
  380. }
  381. return retval;
  382. }
  383. // Same as split, except the find char is cut completely.
  384. String String::lSpliceChar(const char *findval)
  385. {
  386. if (val == NULL) return String();
  387. //CUT // Auto-scope reference allows us to avoid a copy.
  388. //CUT String & retval = lSplitChar(findval);
  389. //BU gcc doesn't agree with you and neither do I :/
  390. String retval = lSplitChar(findval);
  391. // We need to strip the findval char, which is the end char.
  392. int end = retval.len();
  393. int num = STRLEN(findval);
  394. if (end)
  395. {
  396. for (int i = 0; i < num; i++)
  397. {
  398. if (retval.val[end - 1] == findval[i])
  399. {
  400. retval.val[end - 1] = 0;
  401. }
  402. }
  403. }
  404. return retval;
  405. }
  406. String String::rSpliceChar(char findval)
  407. {
  408. if (val == NULL) return String();
  409. //CUT // Auto-scope reference allows us to avoid a copy.
  410. //CUT String & retval = rSplitChar(findval);
  411. //BU gcc doesn't agree with you and neither do I :/
  412. String retval = rSplitChar(findval);
  413. // We need to strip the findval char, which is the first char.
  414. // (But we still check for empty string:)
  415. size_t end = retval.len();
  416. if (end)
  417. {
  418. if (retval.val[0] == findval)
  419. {
  420. #if USE == FAST_METHODS
  421. size_t len = strlen(retval.val + 1);
  422. MEMCPY(retval.val, retval.val + 1, len + 1);
  423. #elif USE == SAFE_METHODS
  424. String temp(retval.val + 1);
  425. retval = temp;
  426. #endif
  427. return retval;
  428. }
  429. }
  430. return retval;
  431. }
  432. String String::rSpliceChar(const char *findval)
  433. {
  434. if (val == NULL) return String();
  435. //CUT // Auto-scope reference allows us to avoid a copy.
  436. //CUT String & retval = rSplitChar(findval);
  437. //BU gcc doesn't agree with you and neither do I :/
  438. String retval = rSplitChar(findval);
  439. // We need to strip the findval char, which is the first char.
  440. // (But we still check for empty string:)
  441. size_t end = retval.len();
  442. size_t num = STRLEN(findval);
  443. if (end)
  444. {
  445. for (size_t i = 0; i < num; i++)
  446. {
  447. if (retval.val[0] == findval[i])
  448. {
  449. #if USE == FAST_METHODS
  450. size_t len = strlen(retval.val + 1);
  451. MEMCPY(retval.val, retval.val + 1, len + 1);
  452. #elif USE == SAFE_METHODS
  453. String temp(retval.val + 1);
  454. retval = temp;
  455. #endif
  456. return retval;
  457. }
  458. }
  459. }
  460. return retval;
  461. }
  462. int String::replace(const char *find, const char *replace)
  463. {
  464. if (len() == 0 || find == NULL || replace == NULL) return 0;
  465. int find_count = 0;
  466. char *p, *p2;
  467. int rep_len = STRLEN( replace );
  468. int find_len = STRLEN( find );
  469. int size_diff = rep_len - find_len;
  470. if ( size_diff == 0 )
  471. {
  472. p = val;
  473. while ( p = STRSTR( p, find ) )
  474. {
  475. STRNCPY( p, replace, rep_len );
  476. p += find_len;
  477. find_count++;
  478. }
  479. }
  480. else
  481. {
  482. char *new_buf, *in;
  483. p = val;
  484. while ( p = STRSTR( p, find ) )
  485. {
  486. find_count++;
  487. p += find_len;
  488. }
  489. new_buf = (char *)MALLOC( len() + find_count * size_diff + 1 );
  490. p = val;
  491. in = new_buf;
  492. while ( p2 = STRSTR( p, find ) )
  493. {
  494. STRNCPY( in, p, (int)(p2 - p) );
  495. in += p2 - p;
  496. STRNCPY( in, replace, rep_len );
  497. in += rep_len;
  498. p = p2 + find_len;
  499. }
  500. STRCPY( in, p );
  501. new_buf[ len() + find_count * size_diff ] = 0;
  502. // just swap buffers
  503. FREE(val);
  504. val = new_buf;
  505. }
  506. return find_count;
  507. }
  508. int String::replaceNumericField(int value, int fieldchar)
  509. {
  510. if (val == NULL || *val == '\0') return 0;
  511. int nrep = 0;
  512. for (const char *p = val; *p; p++)
  513. {
  514. if (*p == fieldchar) nrep++;
  515. else if (nrep) break;
  516. }
  517. if (nrep == 0) return 0; // no field found
  518. String rc;
  519. char fc[2] = { 0, 0 };
  520. fc[0] = fieldchar;
  521. for (int i = 0; i < nrep; i++) rc.cat(fc);
  522. StringPrintf fmt("%%0%0dd", nrep);
  523. StringPrintf replacement(fmt.getValue(), value);
  524. return replace(rc, replacement);
  525. }
  526. #undef USE
  527. #undef SAFE_METHODS
  528. #undef FAST_METHODS
  529. int String::numCharacters()
  530. {
  531. // count newsize characters over how many bytes?
  532. int count, bytes;
  533. for (bytes = 0, count = 0; val[bytes]; count++, bytes++)
  534. {
  535. // If we encounter a lead byte, skip over the trail bytes.
  536. switch (val[bytes] & 0xC0)
  537. {
  538. case 0x80: // trail bytes
  539. // THIS SHOULD NEVER EVER EVER EVER HAPPEN!
  540. // but we'll fall through anyhow, just in case someone
  541. // sends us non-UTF8.
  542. case 0xC0: // lead bytes
  543. do
  544. {
  545. bytes++;
  546. if (val[bytes] == 0)
  547. {
  548. // if people are giving us lame encodings, break here.
  549. break;
  550. }
  551. }
  552. while ((val[bytes + 1] & 0xC0) == 0x80);
  553. break;
  554. }
  555. }
  556. return count;
  557. }
  558. void String::trunc(int newlen)
  559. {
  560. if (val == NULL) return ;
  561. int oldlen = numCharacters();
  562. if (newlen < 0) newlen = MAX(oldlen + newlen, 0);
  563. if (newlen >= oldlen) return ;
  564. // count newsize characters over how many bytes?
  565. int count, bytes;
  566. for (bytes = 0, count = 0; count < newlen; count++, bytes++)
  567. {
  568. // If we encounter a lead byte, skip over the trail bytes.
  569. switch (val[bytes] & 0xC0)
  570. {
  571. case 0x80: // trail bytes
  572. // THIS SHOULD NEVER EVER EVER EVER HAPPEN!
  573. // but we'll fall through anyhow, just in case someone
  574. // sends us non-UTF8.
  575. case 0xC0: // lead bytes
  576. do
  577. {
  578. bytes++;
  579. }
  580. while ((val[bytes + 1] & 0xC0) == 0x80);
  581. break;
  582. }
  583. }
  584. val[bytes] = 0;
  585. }
  586. void String::trim(const char *whitespace, int left, int right)
  587. {
  588. if (val == NULL) return ;
  589. if (left)
  590. { // trim left
  591. for (;;)
  592. {
  593. int restart = 0;
  594. const char *p;
  595. for (p = whitespace; *p; p++)
  596. {
  597. if (*p == val[0])
  598. {
  599. STRCPY(val, val + 1);
  600. restart = 1;
  601. break;
  602. }
  603. }
  604. if (!restart) break;
  605. }
  606. } //left
  607. if (right)
  608. {
  609. char *ptr = val;
  610. while (ptr && *ptr) ptr++;
  611. ptr--;
  612. if (ptr <= val) return ;
  613. for (; ptr > val; ptr--)
  614. {
  615. const char *p;
  616. for (p = whitespace; *p; p++)
  617. {
  618. if (*p == *ptr)
  619. {
  620. *ptr = '\0';
  621. break;
  622. }
  623. }
  624. if (!*p) break;
  625. }
  626. } //right
  627. }
  628. int String::va_sprintf(const char *format, va_list args)
  629. {
  630. if (!format) return 0;
  631. va_list saveargs = args;
  632. // roughly evaluate size of dest string
  633. const char *p = format;
  634. int length = 0;
  635. while (p && *p)
  636. {
  637. if (*(p++) != '%') length++;
  638. else
  639. {
  640. void *arg = va_arg(args, void *);
  641. for (;;)
  642. {
  643. const char f = *p++;
  644. if (f == 'c') length++;
  645. else if (f == 'i') length += 16;
  646. else if (f == 'u') length += 16;
  647. else if (f == 'f') length += 64;
  648. else if (f == 'd' || f == 'f') length += 64;
  649. else if (f == 'x') length += 32; // Hex with LC Alphas: 0x0009a64c
  650. else if (f == 'X') length += 32; // Hex with UC Alphas: 0x0009A64C
  651. else if (f == 's')
  652. { // ::vsrintf can properly handle null.
  653. if (arg == NULL)
  654. {
  655. length += STRLEN("(null)"); // Just to be explicit.
  656. }
  657. else
  658. {
  659. length += STRLEN((const char *)arg);
  660. }
  661. }
  662. else if (f == 'S')
  663. { // ::vsrintf can properly handle null.
  664. if (arg == NULL)
  665. {
  666. length += (int)wcslen(L"(null)"); // Just to be explicit.
  667. }
  668. else
  669. {
  670. length += (int)wcslen((const wchar_t *)arg);
  671. }
  672. }
  673. else if (ISDIGIT(f)) continue;
  674. else if (f == '.') continue;
  675. else if (f == '%') length++;
  676. else ASSERTPR(0, "undefined format passed to stringprintf!");
  677. break;
  678. }
  679. }
  680. }
  681. if (val)
  682. {
  683. if (len() < length)
  684. val = (char *)REALLOC(val, length + 1);
  685. }
  686. else val = (char *)MALLOC(length + 1);
  687. // now write the string in val
  688. int real_len = ::vsprintf_s(val, length + 1, format, saveargs);
  689. ASSERTPR(real_len <= length, "String.printf overflow");
  690. return real_len;
  691. }
  692. void String::purge()
  693. {
  694. FREE(val);
  695. val = NULL;
  696. }
  697. // swaps buffers with another string
  698. void String::swap(String *swapper)
  699. {
  700. char *tempChar = swapper->val;
  701. swapper->val = val;
  702. val = tempChar;
  703. }
  704. void String::swap(String &swapper) // swaps buffers with another string
  705. {
  706. char *tempChar = swapper.val;
  707. swapper.val = val;
  708. val = tempChar;
  709. }
  710. // take ownership of a buffer
  711. void String::own(char *swapper)
  712. {
  713. if (val)
  714. FREE(val);
  715. val = swapper;
  716. }
  717. const char *String::catPostSeparator(const char *value, const char separator)
  718. {
  719. if (value == NULL || *value == 0 || separator == 0) return getValue();
  720. int oldLen = val ? STRLEN(val) : 0;
  721. int newLen = STRLEN(value);
  722. val = (char *)REALLOC(val, oldLen + newLen + 1 + 1); // +1 for separator, +1 for null character
  723. STRCPY(val + oldLen, value);
  724. val[oldLen + newLen] = separator; // add the separator
  725. val[oldLen + newLen + 1] = 0; // null terminate
  726. return val;
  727. }
  728. const char *String::catPreSeparator(const char separator, const char *value)
  729. {
  730. if (value == NULL || *value == 0 || separator == 0) return getValue();
  731. int oldLen = val ? STRLEN(val) : 0;
  732. int newLen = STRLEN(value);
  733. val = (char *)REALLOC(val, oldLen + newLen + 1 + 1); // +1 for separator, +1 for null character
  734. val[oldLen] = separator; // add the separator
  735. STRCPY(val + oldLen + 1, value); // +1 for separator (goes first)
  736. val[oldLen + newLen + 1] = 0; // null terminate
  737. return val;
  738. }
  739. void String::AppendPath(const char *path)
  740. {
  741. catPreSeparator('/', path);
  742. }
  743. StringPrintf::StringPrintf(const char *format, ...)
  744. {
  745. va_list args;
  746. va_start (args, format);
  747. va_sprintf(format, args);
  748. va_end(args);
  749. }
  750. StringPrintf::StringPrintf(int value)
  751. {
  752. *this += value;
  753. }
  754. StringPrintf::StringPrintf(double value)
  755. {
  756. // TODO: review to use locale variant...
  757. char* locale = _strdup(setlocale(LC_NUMERIC, NULL));
  758. setlocale(LC_NUMERIC, "C");
  759. *this += StringPrintf("%f", value);
  760. if (locale)
  761. {
  762. setlocale(LC_NUMERIC, locale);
  763. free(locale);
  764. }
  765. }
  766. StringPrintf::StringPrintf(GUID g)
  767. {
  768. char splab[nsGUID::GUID_STRLEN + 1] = {0};
  769. nsGUID::toChar(g, splab);
  770. cat(splab);
  771. }
  772. _DebugString::_DebugString(const char *format, ...)
  773. {
  774. va_list args;
  775. va_start (args, format);
  776. va_sprintf(format, args);
  777. va_end(args);
  778. debugPrint();
  779. }
  780. _DebugString::_DebugString(const String &s) : String(s)
  781. {
  782. debugPrint();
  783. }
  784. _DebugString::_DebugString(const String *s) : String(s)
  785. {
  786. debugPrint();
  787. }
  788. void _DebugString::debugPrint()
  789. {
  790. #ifdef _WIN32
  791. OutputDebugStringA(getValue());
  792. if (lastChar() != '\n') OutputDebugStringA("\n");
  793. #else
  794. #warning port me
  795. #endif
  796. }
  797. int StringComparator::compareItem(String *p1, String* p2)
  798. {
  799. return STRCMP(p1->getValue(), p2->getValue());
  800. }
  801. int StringComparator::compareAttrib(const wchar_t *attrib, String *item)
  802. {
  803. return STRCMP((const char *)attrib, item->getValue());
  804. }