/vavoom-1.33/libs/core/str.cpp

# · C++ · 1217 lines · 801 code · 120 blank · 296 comment · 196 complexity · 135c25aa8f092ea9bcf86414d1909e83 MD5 · raw file

  1. //**************************************************************************
  2. //**
  3. //** ## ## ## ## ## #### #### ### ###
  4. //** ## ## ## ## ## ## ## ## ## ## #### ####
  5. //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
  6. //** ## ## ######## ## ## ## ## ## ## ## ### ##
  7. //** ### ## ## ### ## ## ## ## ## ##
  8. //** # ## ## # #### #### ## ##
  9. //**
  10. //** $Id: str.cpp 4352 2010-12-20 03:14:10Z firebrand_kh $
  11. //**
  12. //** Copyright (C) 1999-2010 J?nis Legzdi?š
  13. //**
  14. //** This program is free software; you can redistribute it and/or
  15. //** modify it under the terms of the GNU General Public License
  16. //** as published by the Free Software Foundation; either version 2
  17. //** of the License, or (at your option) any later version.
  18. //**
  19. //** This program is distributed in the hope that it will be useful,
  20. //** but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. //** GNU General Public License for more details.
  23. //**
  24. //**************************************************************************
  25. //
  26. // Dynamic string class.
  27. //
  28. //**************************************************************************
  29. // HEADER FILES ------------------------------------------------------------
  30. #include "core.h"
  31. #include <cctype>
  32. // MACROS ------------------------------------------------------------------
  33. #if !defined _WIN32 && !defined DJGPP
  34. #undef stricmp // Allegro defines them
  35. #undef strnicmp
  36. #define stricmp strcasecmp
  37. #define strnicmp strncasecmp
  38. #endif
  39. // TYPES -------------------------------------------------------------------
  40. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  41. // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
  42. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  43. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  44. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  45. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  46. static char va_buffer[4][1024];
  47. static int va_bufnum;
  48. // CODE --------------------------------------------------------------------
  49. //==========================================================================
  50. //
  51. // VStr::VStr
  52. //
  53. //==========================================================================
  54. VStr::VStr(const VStr& InStr, int Start, int Len)
  55. : Str(NULL)
  56. {
  57. check(Start >= 0);
  58. check(Start <= (int)InStr.Length());
  59. check(Len >= 0);
  60. check(Start + Len <= (int)InStr.Length());
  61. if (Len)
  62. {
  63. Resize(Len);
  64. NCpy(Str, InStr.Str + Start, Len);
  65. }
  66. }
  67. //==========================================================================
  68. //
  69. // VStr::Resize
  70. //
  71. //==========================================================================
  72. void VStr::Resize(int NewLen)
  73. {
  74. guard(VStr::Resize);
  75. check(NewLen >= 0);
  76. if ((size_t)NewLen == Length())
  77. {
  78. // Same length, use existing buffer.
  79. return;
  80. }
  81. if (!NewLen)
  82. {
  83. // Free string.
  84. if (Str)
  85. {
  86. delete[] (Str - sizeof(int));
  87. Str = NULL;
  88. }
  89. }
  90. else
  91. {
  92. // Allocate memory.
  93. int AllocLen = sizeof(int) + NewLen + 1;
  94. char* NewStr = (new char[AllocLen]) + sizeof(int);
  95. if (Str)
  96. {
  97. size_t Len = Min(Length(), (size_t)NewLen);
  98. NCpy(NewStr, Str, Len);
  99. delete[] (Str - sizeof(int));
  100. Str = NULL;
  101. }
  102. Str = NewStr;
  103. // Set length.
  104. ((int*)Str)[-1] = NewLen;
  105. // Set terminator.
  106. Str[NewLen] = 0;
  107. }
  108. unguard;
  109. }
  110. //==========================================================================
  111. //
  112. // VStr::StartsWith
  113. //
  114. //==========================================================================
  115. bool VStr::StartsWith(const char* S) const
  116. {
  117. guard(VStr::StartsWith);
  118. size_t l = Length(S);
  119. if (l > Length())
  120. {
  121. return false;
  122. }
  123. return NCmp(**this, S, l) == 0;
  124. unguard;
  125. }
  126. //==========================================================================
  127. //
  128. // VStr::StartsWith
  129. //
  130. //==========================================================================
  131. bool VStr::StartsWith(const VStr& S) const
  132. {
  133. guard(VStr::StartsWith);
  134. size_t l = S.Length();
  135. if (l > Length())
  136. {
  137. return false;
  138. }
  139. return NCmp(**this, *S, l) == 0;
  140. unguard;
  141. }
  142. //==========================================================================
  143. //
  144. // VStr::EndsWith
  145. //
  146. //==========================================================================
  147. bool VStr::EndsWith(const char* S) const
  148. {
  149. guard(VStr::EndsWith);
  150. size_t l = Length(S);
  151. if (l > Length())
  152. {
  153. return false;
  154. }
  155. return NCmp(**this + Length() - l, S, l) == 0;
  156. unguard;
  157. }
  158. //==========================================================================
  159. //
  160. // VStr::EndsWith
  161. //
  162. //==========================================================================
  163. bool VStr::EndsWith(const VStr& S) const
  164. {
  165. guard(VStr::EndsWith);
  166. size_t l = S.Length();
  167. if (l > Length())
  168. {
  169. return false;
  170. }
  171. return NCmp(**this + Length() - l, *S, l) == 0;
  172. unguard;
  173. }
  174. //==========================================================================
  175. //
  176. // VStr::ToLower
  177. //
  178. //==========================================================================
  179. VStr VStr::ToLower() const
  180. {
  181. guard(VStr::ToLower);
  182. if (!Str)
  183. {
  184. return VStr();
  185. }
  186. VStr Ret;
  187. int l = int(Length());
  188. Ret.Resize(l);
  189. for (int i = 0; i < l; i++)
  190. {
  191. Ret.Str[i] = ToLower(Str[i]);
  192. }
  193. return Ret;
  194. unguard;
  195. }
  196. //==========================================================================
  197. //
  198. // VStr::ToUpper
  199. //
  200. //==========================================================================
  201. VStr VStr::ToUpper() const
  202. {
  203. guard(VStr::ToUpper);
  204. if (!Str)
  205. {
  206. return VStr();
  207. }
  208. VStr Ret;
  209. int l = int(Length());
  210. Ret.Resize(l);
  211. for (int i = 0; i < l; i++)
  212. {
  213. Ret.Str[i] = ToUpper(Str[i]);
  214. }
  215. return Ret;
  216. unguard;
  217. }
  218. //==========================================================================
  219. //
  220. // VStr::IndexOf
  221. //
  222. //==========================================================================
  223. int VStr::IndexOf(char C) const
  224. {
  225. guard(VStr::IndexOf);
  226. int l = int(Length());
  227. for (int i = 0; i < l; i++)
  228. {
  229. if (Str[i] == C)
  230. {
  231. return i;
  232. }
  233. }
  234. return -1;
  235. unguard;
  236. }
  237. //==========================================================================
  238. //
  239. // VStr::IndexOf
  240. //
  241. //==========================================================================
  242. int VStr::IndexOf(const char* S) const
  243. {
  244. guard(VStr::IndexOf);
  245. int sl = int(Length(S));
  246. if (!sl)
  247. {
  248. return -1;
  249. }
  250. int l = int(Length());
  251. for (int i = 0; i <= l - sl; i++)
  252. {
  253. if (NCmp(Str + i, S, sl) == 0)
  254. {
  255. return i;
  256. }
  257. }
  258. return -1;
  259. unguard;
  260. }
  261. //==========================================================================
  262. //
  263. // VStr::IndexOf
  264. //
  265. //==========================================================================
  266. int VStr::IndexOf(const VStr& S) const
  267. {
  268. guard(VStr::IndexOf);
  269. int sl = int(S.Length());
  270. if (!sl)
  271. {
  272. return -1;
  273. }
  274. int l = int(Length());
  275. for (int i = 0; i <= l - sl; i++)
  276. {
  277. if (NCmp(Str + i, *S, sl) == 0)
  278. {
  279. return i;
  280. }
  281. }
  282. return -1;
  283. unguard;
  284. }
  285. //==========================================================================
  286. //
  287. // VStr::LastIndexOf
  288. //
  289. //==========================================================================
  290. int VStr::LastIndexOf(char C) const
  291. {
  292. guard(VStr::LastIndexOf);
  293. for (int i = int(Length()) - 1; i >= 0; i--)
  294. {
  295. if (Str[i] == C)
  296. {
  297. return i;
  298. }
  299. }
  300. return -1;
  301. unguard;
  302. }
  303. //==========================================================================
  304. //
  305. // VStr::LastIndexOf
  306. //
  307. //==========================================================================
  308. int VStr::LastIndexOf(const char* S) const
  309. {
  310. guard(VStr::LastIndexOf);
  311. int sl = int(Length(S));
  312. if (!sl)
  313. {
  314. return -1;
  315. }
  316. int l = int(Length());
  317. for (int i = l - sl; i >= 0; i--)
  318. {
  319. if (NCmp(Str + i, S, sl) == 0)
  320. {
  321. return i;
  322. }
  323. }
  324. return -1;
  325. unguard;
  326. }
  327. //==========================================================================
  328. //
  329. // VStr::LastIndexOf
  330. //
  331. //==========================================================================
  332. int VStr::LastIndexOf(const VStr& S) const
  333. {
  334. guard(VStr::LastIndexOf);
  335. int sl = int(S.Length());
  336. if (!sl)
  337. {
  338. return -1;
  339. }
  340. int l = int(Length());
  341. for (int i = l - sl; i >= 0; i--)
  342. {
  343. if (NCmp(Str + i, *S, sl) == 0)
  344. {
  345. return i;
  346. }
  347. }
  348. return -1;
  349. unguard;
  350. }
  351. //==========================================================================
  352. //
  353. // VStr::Replace
  354. //
  355. //==========================================================================
  356. VStr VStr::Replace(const char* Search, const char* Replacement) const
  357. {
  358. guard(VStr::Replace);
  359. if (!Length())
  360. {
  361. // Nothing to replace in an empty string.
  362. return *this;
  363. }
  364. size_t SLen = Length(Search);
  365. size_t RLen = Length(Replacement);
  366. if (!SLen)
  367. {
  368. // Nothing to search for.
  369. return *this;
  370. }
  371. VStr Ret = *this;
  372. size_t i = 0;
  373. while (i <= Ret.Length() - SLen)
  374. {
  375. if (!NCmp(Ret.Str + i, Search, SLen))
  376. {
  377. // If search and replace strings are of the same size, we can
  378. // just copy the data and avoid memory allocations.
  379. if (SLen == RLen)
  380. {
  381. memcpy(Ret.Str + i, Replacement, RLen);
  382. }
  383. else
  384. {
  385. Ret = VStr(Ret, 0, int(i)) + Replacement +
  386. VStr(Ret, int(i + SLen), int(Ret.Length() - i - SLen));
  387. }
  388. i += RLen;
  389. }
  390. else
  391. {
  392. i++;
  393. }
  394. }
  395. return Ret;
  396. unguard;
  397. }
  398. //==========================================================================
  399. //
  400. // VStr::Replace
  401. //
  402. //==========================================================================
  403. VStr VStr::Replace(const VStr& Search, const VStr& Replacement) const
  404. {
  405. guard(VStr::Replace);
  406. if (!Length())
  407. {
  408. // Nothing to replace in an empty string.
  409. return *this;
  410. }
  411. size_t SLen = Search.Length();
  412. size_t RLen = Replacement.Length();
  413. if (!SLen)
  414. {
  415. // Nothing to search for.
  416. return *this;
  417. }
  418. VStr Ret = *this;
  419. size_t i = 0;
  420. while (i <= Ret.Length() - SLen)
  421. {
  422. if (!NCmp(Ret.Str + i, *Search, SLen))
  423. {
  424. // If search and replace strings are of the same size, we can
  425. // just copy the data and avoid memory allocations.
  426. if (SLen == RLen)
  427. {
  428. memcpy(Ret.Str + i, *Replacement, RLen);
  429. }
  430. else
  431. {
  432. Ret = VStr(Ret, 0, int(i)) + Replacement +
  433. VStr(Ret, int(i + SLen), int(Ret.Length() - i - SLen));
  434. }
  435. i += RLen;
  436. }
  437. else
  438. {
  439. i++;
  440. }
  441. }
  442. return Ret;
  443. unguard;
  444. }
  445. //==========================================================================
  446. //
  447. // VStr::Utf8Substring
  448. //
  449. //==========================================================================
  450. VStr VStr::Utf8Substring(int Start, int Len) const
  451. {
  452. check(Start >= 0);
  453. check(Start <= (int)Utf8Length());
  454. check(Len >= 0);
  455. check(Start + Len <= (int)Utf8Length());
  456. if (!Len)
  457. {
  458. return VStr();
  459. }
  460. int RealStart = int(ByteLengthForUtf8(Str, Start));
  461. int RealLen = int(ByteLengthForUtf8(Str, Start + Len) - RealStart);
  462. return VStr(*this, RealStart, RealLen);
  463. }
  464. //==========================================================================
  465. //
  466. // VStr::Split
  467. //
  468. //==========================================================================
  469. void VStr::Split(char C, TArray<VStr>& A) const
  470. {
  471. guard(VStr::Split);
  472. A.Clear();
  473. if (!Str)
  474. {
  475. return;
  476. }
  477. int Start = 0;
  478. int Len = int(Length());
  479. for (int i = 0; i <= Len; i++)
  480. {
  481. if (i == Len || Str[i] == C)
  482. {
  483. if (Start != i)
  484. {
  485. A.Append(VStr(*this, Start, i - Start));
  486. }
  487. Start = i + 1;
  488. }
  489. }
  490. unguard;
  491. }
  492. //==========================================================================
  493. //
  494. // VStr::Split
  495. //
  496. //==========================================================================
  497. void VStr::Split(const char* Chars, TArray<VStr>& A) const
  498. {
  499. guard(VStr::Split);
  500. A.Clear();
  501. if (!Str)
  502. {
  503. return;
  504. }
  505. int Start = 0;
  506. int Len = int(Length());
  507. for (int i = 0; i <= Len; i++)
  508. {
  509. bool DoSplit = i == Len;
  510. for (const char* pChar = Chars; !DoSplit && *pChar; pChar++)
  511. {
  512. DoSplit = Str[i] == *pChar;
  513. }
  514. if (DoSplit)
  515. {
  516. if (Start != i)
  517. {
  518. A.Append(VStr(*this, Start, i - Start));
  519. }
  520. Start = i + 1;
  521. }
  522. }
  523. unguard;
  524. }
  525. //==========================================================================
  526. //
  527. // VStr::IsValidUtf8
  528. //
  529. //==========================================================================
  530. bool VStr::IsValidUtf8() const
  531. {
  532. guard(VStr::IsValidUtf8);
  533. if (!Str)
  534. {
  535. return true;
  536. }
  537. for (const char* c = Str; *c;)
  538. {
  539. if ((*c & 0x80) == 0)
  540. {
  541. c++;
  542. }
  543. else if ((*c & 0xe0) == 0xc0)
  544. {
  545. if ((c[1] & 0xc0) != 0x80)
  546. {
  547. return false;
  548. }
  549. c += 2;
  550. }
  551. else if ((*c & 0xf0) == 0xe0)
  552. {
  553. if ((c[1] & 0xc0) != 0x80 || (c[2] & 0xc0) != 0x80)
  554. {
  555. return false;
  556. }
  557. c += 3;
  558. }
  559. else if ((*c & 0xf8) == 0xf0)
  560. {
  561. if ((c[1] & 0xc0) != 0x80 || (c[2] & 0xc0) != 0x80 ||
  562. (c[3] & 0xc0) != 0x80)
  563. {
  564. return false;
  565. }
  566. c += 4;
  567. }
  568. else
  569. {
  570. return false;
  571. }
  572. }
  573. return true;
  574. unguard;
  575. }
  576. //==========================================================================
  577. //
  578. // VStr::Latin1ToUtf8
  579. //
  580. //==========================================================================
  581. VStr VStr::Latin1ToUtf8() const
  582. {
  583. guard(VStr::Latin1ToUtf8);
  584. VStr Ret;
  585. for (size_t i = 0; i < Length(); i++)
  586. {
  587. Ret += FromChar((vuint8)Str[i]);
  588. }
  589. return Ret;
  590. unguard;
  591. }
  592. //==========================================================================
  593. //
  594. // VStr::EvalEscapeSequences
  595. //
  596. //==========================================================================
  597. VStr VStr::EvalEscapeSequences() const
  598. {
  599. guard(VStr::EvalEscapeSequences);
  600. VStr Ret;
  601. char Val;
  602. for (const char* c = **this; *c; c++)
  603. {
  604. if (*c == '\\')
  605. {
  606. c++;
  607. switch (*c)
  608. {
  609. case 't':
  610. Ret += '\t';
  611. break;
  612. case 'n':
  613. Ret += '\n';
  614. break;
  615. case 'r':
  616. Ret += '\r';
  617. break;
  618. case 'c':
  619. Ret += TEXT_COLOUR_ESCAPE;
  620. break;
  621. case 'x':
  622. Val = 0;
  623. c++;
  624. for (int i = 0; i < 2; i++)
  625. {
  626. if (*c >= '0' && *c <= '9')
  627. Val = (Val << 4) + *c - '0';
  628. else if (*c >= 'a' && *c <= 'f')
  629. Val = (Val << 4) + 10 + *c - 'a';
  630. else if (*c >= 'A' && *c <= 'F')
  631. Val = (Val << 4) + 10 + *c - 'A';
  632. else
  633. break;
  634. c++;
  635. }
  636. c--;
  637. Ret += Val;
  638. break;
  639. case '0':
  640. case '1':
  641. case '2':
  642. case '3':
  643. case '4':
  644. case '5':
  645. case '6':
  646. case '7':
  647. Val = 0;
  648. for (int i = 0; i < 3; i++)
  649. {
  650. if (*c >= '0' && *c <= '7')
  651. Val = (Val << 3) + *c - '0';
  652. else
  653. break;
  654. c++;
  655. }
  656. c--;
  657. Ret += Val;
  658. break;
  659. case '\n':
  660. break;
  661. case 0:
  662. c--;
  663. break;
  664. default:
  665. Ret += *c;
  666. break;
  667. }
  668. }
  669. else
  670. {
  671. Ret += *c;
  672. }
  673. }
  674. return Ret;
  675. unguard;
  676. }
  677. //==========================================================================
  678. //
  679. // VStr::RemoveColours
  680. //
  681. //==========================================================================
  682. VStr VStr::RemoveColours() const
  683. {
  684. guard(VStr::RemoveColours);
  685. VStr Ret;
  686. for (const char* c = **this; *c; c++)
  687. {
  688. if (*c == TEXT_COLOUR_ESCAPE)
  689. {
  690. if (c[1])
  691. {
  692. c++;
  693. }
  694. if (*c == '[')
  695. {
  696. while (c[1] && *c != ']')
  697. {
  698. c++;
  699. }
  700. }
  701. continue;
  702. }
  703. Ret += *c;
  704. }
  705. return Ret;
  706. unguard;
  707. }
  708. //==========================================================================
  709. //
  710. // VStr::ExtractFilePath
  711. //
  712. //==========================================================================
  713. VStr VStr::ExtractFilePath() const
  714. {
  715. guard(FL_ExtractFilePath);
  716. const char* src = Str + Length() - 1;
  717. //
  718. // back up until a \ or the start
  719. //
  720. while (src != Str && *(src - 1) != '/' && *(src - 1) != '\\')
  721. src--;
  722. return VStr(*this, 0, src - Str);
  723. unguard;
  724. }
  725. //==========================================================================
  726. //
  727. // VStr:ExtractFileName
  728. //
  729. //==========================================================================
  730. VStr VStr::ExtractFileName() const
  731. {
  732. guard(VStr:ExtractFileName);
  733. const char* src = Str + Length() - 1;
  734. //
  735. // back up until a \ or the start
  736. //
  737. while (src != Str && *(src - 1) != '/' && *(src - 1) != '\\')
  738. src--;
  739. return src;
  740. unguard;
  741. }
  742. //==========================================================================
  743. //
  744. // VStr::ExtractFileBase
  745. //
  746. //==========================================================================
  747. VStr VStr::ExtractFileBase() const
  748. {
  749. guard(VStr::ExtractFileBase);
  750. int i = int(Length() - 1);
  751. // back up until a \ or the start
  752. while (i && Str[i - 1] != '\\' && Str[i - 1] != '/')
  753. {
  754. i--;
  755. }
  756. // copy up to eight characters
  757. int start = i;
  758. int length = 0;
  759. while (Str[i] && Str[i] != '.')
  760. {
  761. if (++length == 9)
  762. Sys_Error("Filename base of %s >8 chars", Str);
  763. i++;
  764. }
  765. return VStr(*this, start, length);
  766. unguard;
  767. }
  768. //==========================================================================
  769. //
  770. // VStr::ExtractFileExtension
  771. //
  772. //==========================================================================
  773. VStr VStr::ExtractFileExtension() const
  774. {
  775. guard(VStr::ExtractFileExtension);
  776. const char* src = Str + Length() - 1;
  777. //
  778. // back up until a . or the start
  779. //
  780. while (src != Str && *(src - 1) != '.')
  781. src--;
  782. if (src == Str)
  783. {
  784. return VStr(); // no extension
  785. }
  786. return src;
  787. unguard;
  788. }
  789. //==========================================================================
  790. //
  791. // VStr::StripExtension
  792. //
  793. //==========================================================================
  794. VStr VStr::StripExtension() const
  795. {
  796. guard(VStr::StripExtension);
  797. const char* search = Str + Length() - 1;
  798. while (*search != '/' && *search != '\\' && search != Str)
  799. {
  800. if (*search == '.')
  801. {
  802. return VStr(*this, 0, search - Str);
  803. }
  804. search--;
  805. }
  806. return *this;
  807. unguard;
  808. }
  809. //==========================================================================
  810. //
  811. // VStr::DefaultPath
  812. //
  813. //==========================================================================
  814. VStr VStr::DefaultPath(const VStr& basepath) const
  815. {
  816. guard(VStr::DefaultPath);
  817. if (Str[0] == '/')
  818. {
  819. return *this; // absolute path location
  820. }
  821. return basepath + *this;
  822. unguard;
  823. }
  824. //==========================================================================
  825. //
  826. // VStr.DefaultExtension
  827. //
  828. //==========================================================================
  829. VStr VStr::DefaultExtension(const VStr& extension) const
  830. {
  831. guard(VStr::DefaultExtension);
  832. //
  833. // if path doesn't have a .EXT, append extension
  834. // (extension should include the .)
  835. //
  836. const char* src = Str + Length() - 1;
  837. while (*src != '/' && *src != '\\' && src != Str)
  838. {
  839. if (*src == '.')
  840. {
  841. return *this; // it has an extension
  842. }
  843. src--;
  844. }
  845. return *this + extension;
  846. unguard;
  847. }
  848. //==========================================================================
  849. //
  850. // VStr::FixFileSlashes
  851. //
  852. //==========================================================================
  853. VStr VStr::FixFileSlashes() const
  854. {
  855. guard(VStr::FixFileSlashes);
  856. VStr Ret(*this);
  857. int l = int(Length());
  858. for (int i = 0; i < l; i++)
  859. {
  860. if (Ret[i] == '\\')
  861. Ret[i] = '/';
  862. }
  863. return Ret;
  864. unguard;
  865. }
  866. //==========================================================================
  867. //
  868. // VStr::Length
  869. //
  870. //==========================================================================
  871. size_t VStr::Length(const char* S)
  872. {
  873. return strlen(S);
  874. }
  875. //==========================================================================
  876. //
  877. // VStr::Utf8Length
  878. //
  879. //==========================================================================
  880. size_t VStr::Utf8Length(const char* S)
  881. {
  882. guard(VStr::Utf8Length);
  883. size_t Count = 0;
  884. for (const char* c = S; *c; c++)
  885. if ((*c & 0xc0) != 0x80)
  886. Count++;
  887. return Count;
  888. unguard;
  889. }
  890. //==========================================================================
  891. //
  892. // VStr::ByteLengthForUtf8
  893. //
  894. //==========================================================================
  895. size_t VStr::ByteLengthForUtf8(const char* S, size_t N)
  896. {
  897. guard(VStr::ByteLengthForUtf8);
  898. size_t Count = 0;
  899. const char* c;
  900. for (c = S; *c; c++)
  901. {
  902. if ((*c & 0xc0) != 0x80)
  903. {
  904. if (Count == N)
  905. {
  906. return c - S;
  907. }
  908. Count++;
  909. }
  910. }
  911. check(N == Count);
  912. return c - S;
  913. unguard;
  914. }
  915. //==========================================================================
  916. //
  917. // VStr::GetChar
  918. //
  919. //==========================================================================
  920. int VStr::GetChar(const char*& S)
  921. {
  922. guard(VStr::GetChar);
  923. if ((vuint8)*S < 128)
  924. {
  925. return *S++;
  926. }
  927. int Cnt;
  928. int Val;
  929. if ((*S & 0xe0) == 0xc0)
  930. {
  931. Val = *S & 0x1f;
  932. Cnt = 1;
  933. }
  934. else if ((*S & 0xf0) == 0xe0)
  935. {
  936. Val = *S & 0x0f;
  937. Cnt = 2;
  938. }
  939. else if ((*S & 0xf8) == 0xf0)
  940. {
  941. Val = *S & 0x07;
  942. Cnt = 3;
  943. }
  944. else
  945. {
  946. Sys_Error("Not a valid UTF-8");
  947. return 0;
  948. }
  949. S++;
  950. do
  951. {
  952. if ((*S & 0xc0) != 0x80)
  953. Sys_Error("Not a valid UTF-8");
  954. Val = (Val << 6) | (*S & 0x3f);
  955. S++;
  956. }
  957. while (--Cnt);
  958. return Val;
  959. unguard;
  960. }
  961. //==========================================================================
  962. //
  963. // VStr::FromChar
  964. //
  965. //==========================================================================
  966. VStr VStr::FromChar(int C)
  967. {
  968. guard(VStr::FromChar);
  969. char Ret[8];
  970. if (C < 0x80)
  971. {
  972. Ret[0] = C;
  973. Ret[1] = 0;
  974. }
  975. else if (C < 0x800)
  976. {
  977. Ret[0] = 0xc0 | (C & 0x1f);
  978. Ret[1] = 0x80 | ((C >> 5) & 0x3f);
  979. Ret[2] = 0;
  980. }
  981. else if (C < 0x10000)
  982. {
  983. Ret[0] = 0xe0 | (C & 0x0f);
  984. Ret[1] = 0x80 | ((C >> 4) & 0x3f);
  985. Ret[2] = 0x80 | ((C >> 10) & 0x3f);
  986. Ret[3] = 0;
  987. }
  988. else
  989. {
  990. Ret[0] = 0xf0 | (C & 0x07);
  991. Ret[1] = 0x80 | ((C >> 3) & 0x3f);
  992. Ret[2] = 0x80 | ((C >> 9) & 0x3f);
  993. Ret[3] = 0x80 | ((C >> 15) & 0x3f);
  994. Ret[4] = 0;
  995. }
  996. return Ret;
  997. unguard;
  998. }
  999. //==========================================================================
  1000. //
  1001. // VStr::Cmp
  1002. //
  1003. //==========================================================================
  1004. int VStr::Cmp(const char* S1, const char* S2)
  1005. {
  1006. return strcmp(S1, S2);
  1007. }
  1008. //==========================================================================
  1009. //
  1010. // VStr::NCmp
  1011. //
  1012. //==========================================================================
  1013. int VStr::NCmp(const char* S1, const char* S2, size_t N)
  1014. {
  1015. return strncmp(S1, S2, N);
  1016. }
  1017. //==========================================================================
  1018. //
  1019. // VStr::ICmp
  1020. //
  1021. //==========================================================================
  1022. int VStr::ICmp(const char* S1, const char* S2)
  1023. {
  1024. #ifdef WIN32
  1025. return _stricmp(S1, S2);
  1026. #else
  1027. return stricmp(S1, S2);
  1028. #endif
  1029. }
  1030. //==========================================================================
  1031. //
  1032. // VStr::NICmp
  1033. //
  1034. //==========================================================================
  1035. int VStr::NICmp(const char* S1, const char* S2, size_t N)
  1036. {
  1037. #ifdef WIN32
  1038. return _strnicmp(S1, S2, N);
  1039. #else
  1040. return strnicmp(S1, S2, N);
  1041. #endif
  1042. }
  1043. //==========================================================================
  1044. //
  1045. // VStr::Cpy
  1046. //
  1047. //==========================================================================
  1048. void VStr::Cpy(char* Dst, const char* Src)
  1049. {
  1050. strcpy(Dst, Src);
  1051. }
  1052. //==========================================================================
  1053. //
  1054. // VStr::NCpy
  1055. //
  1056. //==========================================================================
  1057. void VStr::NCpy(char* Dst, const char* Src, size_t N)
  1058. {
  1059. strncpy(Dst, Src, N);
  1060. }
  1061. //==========================================================================
  1062. //
  1063. // VStr::ToUpper
  1064. //
  1065. //==========================================================================
  1066. char VStr::ToUpper(char C)
  1067. {
  1068. return toupper(C);
  1069. }
  1070. //==========================================================================
  1071. //
  1072. // VStr::ToLower
  1073. //
  1074. //==========================================================================
  1075. char VStr::ToLower(char C)
  1076. {
  1077. return tolower(C);
  1078. }
  1079. //==========================================================================
  1080. //
  1081. // va
  1082. //
  1083. // Very usefull function from QUAKE
  1084. // Does a varargs printf into a temp buffer, so I don't need to have
  1085. // varargs versions of all text functions.
  1086. // FIXME: make this buffer size safe someday
  1087. //
  1088. //==========================================================================
  1089. char *va(const char *text, ...)
  1090. {
  1091. va_list args;
  1092. va_bufnum = (va_bufnum + 1) & 3;
  1093. va_start(args, text);
  1094. vsprintf(va_buffer[va_bufnum], text, args);
  1095. va_end(args);
  1096. return va_buffer[va_bufnum];
  1097. }