Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

782 lines
18KB

  1. /*
  2. * Carla String
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_STRING_HPP_INCLUDED
  18. #define CARLA_STRING_HPP_INCLUDED
  19. #include "CarlaJuceUtils.hpp"
  20. #ifdef CARLA_OS_HAIKU
  21. namespace std {
  22. using ::snprintf;
  23. }
  24. #endif
  25. // -----------------------------------------------------------------------
  26. // CarlaString class
  27. class CarlaString
  28. {
  29. public:
  30. // -------------------------------------------------------------------
  31. // constructors (no explicit conversions allowed)
  32. /*
  33. * Empty string.
  34. */
  35. explicit CarlaString() noexcept
  36. {
  37. _init();
  38. }
  39. /*
  40. * Simple character.
  41. */
  42. explicit CarlaString(const char c) noexcept
  43. {
  44. char ch[2];
  45. ch[0] = c;
  46. ch[1] = '\0';
  47. _init();
  48. _dup(ch);
  49. }
  50. /*
  51. * Simple char string.
  52. */
  53. explicit CarlaString(char* const strBuf) noexcept
  54. {
  55. _init();
  56. _dup(strBuf);
  57. }
  58. /*
  59. * Simple const char string.
  60. */
  61. explicit CarlaString(const char* const strBuf) noexcept
  62. {
  63. _init();
  64. _dup(strBuf);
  65. }
  66. /*
  67. * Integer.
  68. */
  69. explicit CarlaString(const int value) noexcept
  70. {
  71. char strBuf[0xff+1];
  72. carla_zeroChar(strBuf, 0xff+1);
  73. std::snprintf(strBuf, 0xff, "%d", value);
  74. _init();
  75. _dup(strBuf);
  76. }
  77. /*
  78. * Unsigned integer, possibly in hexadecimal.
  79. */
  80. explicit CarlaString(const uint value, const bool hexadecimal = false) noexcept
  81. {
  82. char strBuf[0xff+1];
  83. carla_zeroChar(strBuf, 0xff+1);
  84. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  85. _init();
  86. _dup(strBuf);
  87. }
  88. /*
  89. * Long integer.
  90. */
  91. explicit CarlaString(const long value) noexcept
  92. {
  93. char strBuf[0xff+1];
  94. carla_zeroChar(strBuf, 0xff+1);
  95. std::snprintf(strBuf, 0xff, "%ld", value);
  96. _init();
  97. _dup(strBuf);
  98. }
  99. /*
  100. * Long unsigned integer, possibly hexadecimal.
  101. */
  102. explicit CarlaString(const ulong value, const bool hexadecimal = false) noexcept
  103. {
  104. char strBuf[0xff+1];
  105. carla_zeroChar(strBuf, 0xff+1);
  106. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  107. _init();
  108. _dup(strBuf);
  109. }
  110. /*
  111. * Long long integer.
  112. */
  113. explicit CarlaString(const long long value) noexcept
  114. {
  115. char strBuf[0xff+1];
  116. carla_zeroChar(strBuf, 0xff+1);
  117. std::snprintf(strBuf, 0xff, "%lld", value);
  118. _init();
  119. _dup(strBuf);
  120. }
  121. /*
  122. * Long long unsigned integer, possibly hexadecimal.
  123. */
  124. explicit CarlaString(const unsigned long long value, const bool hexadecimal = false) noexcept
  125. {
  126. char strBuf[0xff+1];
  127. carla_zeroChar(strBuf, 0xff+1);
  128. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value);
  129. _init();
  130. _dup(strBuf);
  131. }
  132. /*
  133. * Single-precision floating point number.
  134. */
  135. explicit CarlaString(const float value) noexcept
  136. {
  137. char strBuf[0xff+1];
  138. carla_zeroChar(strBuf, 0xff+1);
  139. std::snprintf(strBuf, 0xff, "%f", value);
  140. _init();
  141. _dup(strBuf);
  142. }
  143. /*
  144. * Double-precision floating point number.
  145. */
  146. explicit CarlaString(const double value) noexcept
  147. {
  148. char strBuf[0xff+1];
  149. carla_zeroChar(strBuf, 0xff+1);
  150. std::snprintf(strBuf, 0xff, "%g", value);
  151. _init();
  152. _dup(strBuf);
  153. }
  154. // -------------------------------------------------------------------
  155. // non-explicit constructor
  156. /*
  157. * Create string from another string.
  158. */
  159. CarlaString(const CarlaString& str) noexcept
  160. {
  161. _init();
  162. _dup(str.fBuffer);
  163. }
  164. // -------------------------------------------------------------------
  165. // destructor
  166. /*
  167. * Destructor.
  168. */
  169. ~CarlaString() noexcept
  170. {
  171. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  172. if (fBuffer == _null())
  173. return;
  174. try {
  175. delete[] fBuffer;
  176. } catch(...) {}
  177. fBuffer = nullptr;
  178. }
  179. // -------------------------------------------------------------------
  180. // public methods
  181. /*
  182. * Get length of the string.
  183. */
  184. size_t length() const noexcept
  185. {
  186. return fBufferLen;
  187. }
  188. /*
  189. * Check if the string is empty.
  190. */
  191. bool isEmpty() const noexcept
  192. {
  193. return (fBufferLen == 0);
  194. }
  195. /*
  196. * Check if the string is not empty.
  197. */
  198. bool isNotEmpty() const noexcept
  199. {
  200. return (fBufferLen != 0);
  201. }
  202. /*
  203. * Check if the string contains another string, optionally ignoring case.
  204. */
  205. bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
  206. {
  207. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  208. if (ignoreCase)
  209. {
  210. #ifdef __USE_GNU
  211. return (strcasestr(fBuffer, strBuf) != nullptr);
  212. #else
  213. CarlaString tmp1(fBuffer), tmp2(strBuf);
  214. // memory allocation failed or empty string(s)
  215. if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
  216. return false;
  217. tmp1.toLower();
  218. tmp2.toLower();
  219. return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr);
  220. #endif
  221. }
  222. return (std::strstr(fBuffer, strBuf) != nullptr);
  223. }
  224. /*
  225. * Overloaded function.
  226. */
  227. bool contains(const CarlaString& str, const bool ignoreCase = false) const noexcept
  228. {
  229. return contains(str.fBuffer, ignoreCase);
  230. }
  231. /*
  232. * Check if character at 'pos' is a digit.
  233. */
  234. bool isDigit(const size_t pos) const noexcept
  235. {
  236. CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
  237. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  238. }
  239. /*
  240. * Check if the string starts with the character 'c'.
  241. */
  242. bool startsWith(const char c) const noexcept
  243. {
  244. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  245. return (fBufferLen > 0 && fBuffer[0] == c);
  246. }
  247. /*
  248. * Check if the string starts with the string 'prefix'.
  249. */
  250. bool startsWith(const char* const prefix) const noexcept
  251. {
  252. CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
  253. const size_t prefixLen(std::strlen(prefix));
  254. if (fBufferLen < prefixLen)
  255. return false;
  256. return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
  257. }
  258. /*
  259. * Check if the string starts with the string 'prefix'.
  260. */
  261. bool startsWith(const CarlaString& prefix) const noexcept
  262. {
  263. return startsWith(prefix.fBuffer);
  264. }
  265. /*
  266. * Check if the string ends with the character 'c'.
  267. */
  268. bool endsWith(const char c) const noexcept
  269. {
  270. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  271. return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
  272. }
  273. /*
  274. * Check if the string ends with the string 'suffix'.
  275. */
  276. bool endsWith(const char* const suffix) const noexcept
  277. {
  278. CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
  279. const size_t suffixLen(std::strlen(suffix));
  280. if (fBufferLen < suffixLen)
  281. return false;
  282. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  283. }
  284. /*
  285. * Check if the string ends with the string 'suffix'.
  286. */
  287. bool endsWith(const CarlaString& suffix) const noexcept
  288. {
  289. return endsWith(suffix.fBuffer);
  290. }
  291. /*
  292. * Find the first occurrence of character 'c' in the string.
  293. * Returns "length()" if the character is not found.
  294. */
  295. size_t find(const char c, bool* const found = nullptr) const noexcept
  296. {
  297. if (fBufferLen == 0 || c == '\0')
  298. {
  299. if (found != nullptr)
  300. *found = false;
  301. return fBufferLen;
  302. }
  303. for (size_t i=0; i < fBufferLen; ++i)
  304. {
  305. if (fBuffer[i] == c)
  306. {
  307. if (found != nullptr)
  308. *found = true;
  309. return i;
  310. }
  311. }
  312. if (found != nullptr)
  313. *found = false;
  314. return fBufferLen;
  315. }
  316. /*
  317. * Find the first occurrence of string 'strBuf' in the string.
  318. * Returns "length()" if the string is not found.
  319. */
  320. size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
  321. {
  322. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  323. {
  324. if (found != nullptr)
  325. *found = false;
  326. return fBufferLen;
  327. }
  328. if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
  329. {
  330. const ssize_t ret(subStrBuf - fBuffer);
  331. if (ret < 0)
  332. {
  333. // should never happen!
  334. carla_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret));
  335. if (found != nullptr)
  336. *found = false;
  337. return fBufferLen;
  338. }
  339. if (found != nullptr)
  340. *found = true;
  341. return static_cast<size_t>(ret);
  342. }
  343. if (found != nullptr)
  344. *found = false;
  345. return fBufferLen;
  346. }
  347. /*
  348. * Find the last occurrence of character 'c' in the string.
  349. * Returns "length()" if the character is not found.
  350. */
  351. size_t rfind(const char c, bool* const found = nullptr) const noexcept
  352. {
  353. if (fBufferLen == 0 || c == '\0')
  354. {
  355. if (found != nullptr)
  356. *found = false;
  357. return fBufferLen;
  358. }
  359. for (size_t i=fBufferLen; i > 0; --i)
  360. {
  361. if (fBuffer[i-1] == c)
  362. {
  363. if (found != nullptr)
  364. *found = true;
  365. return i-1;
  366. }
  367. }
  368. if (found != nullptr)
  369. *found = false;
  370. return fBufferLen;
  371. }
  372. /*
  373. * Find the last occurrence of string 'strBuf' in the string.
  374. * Returns "length()" if the string is not found.
  375. */
  376. size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
  377. {
  378. if (found != nullptr)
  379. *found = false;
  380. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  381. return fBufferLen;
  382. const size_t strBufLen(std::strlen(strBuf));
  383. size_t ret = fBufferLen;
  384. const char* tmpBuf = fBuffer;
  385. for (size_t i=0; i < fBufferLen; ++i)
  386. {
  387. if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
  388. {
  389. if (found != nullptr)
  390. *found = true;
  391. break;
  392. }
  393. --ret;
  394. ++tmpBuf;
  395. }
  396. return fBufferLen-ret;
  397. }
  398. /*
  399. * Clear the string.
  400. */
  401. void clear() noexcept
  402. {
  403. truncate(0);
  404. }
  405. /*
  406. * Replace all occurrences of character 'before' with character 'after'.
  407. */
  408. void replace(const char before, const char after) noexcept
  409. {
  410. CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0',);
  411. for (size_t i=0; i < fBufferLen; ++i)
  412. {
  413. if (fBuffer[i] == before)
  414. fBuffer[i] = after;
  415. }
  416. }
  417. /*
  418. * Truncate the string to size 'n'.
  419. */
  420. void truncate(const size_t n) noexcept
  421. {
  422. if (n >= fBufferLen)
  423. return;
  424. for (size_t i=n; i < fBufferLen; ++i)
  425. fBuffer[i] = '\0';
  426. fBufferLen = n;
  427. }
  428. /*
  429. * Convert all non-basic characters to '_'.
  430. */
  431. void toBasic() noexcept
  432. {
  433. for (size_t i=0; i < fBufferLen; ++i)
  434. {
  435. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  436. continue;
  437. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  438. continue;
  439. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  440. continue;
  441. if (fBuffer[i] == '_')
  442. continue;
  443. fBuffer[i] = '_';
  444. }
  445. }
  446. /*
  447. * Convert to all ascii characters to lowercase.
  448. */
  449. void toLower() noexcept
  450. {
  451. static const char kCharDiff('a' - 'A');
  452. for (size_t i=0; i < fBufferLen; ++i)
  453. {
  454. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  455. fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
  456. }
  457. }
  458. /*
  459. * Convert to all ascii characters to uppercase.
  460. */
  461. void toUpper() noexcept
  462. {
  463. static const char kCharDiff('a' - 'A');
  464. for (size_t i=0; i < fBufferLen; ++i)
  465. {
  466. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  467. fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
  468. }
  469. }
  470. /*
  471. * Direct access to the string buffer (read-only).
  472. */
  473. const char* buffer() const noexcept
  474. {
  475. return fBuffer;
  476. }
  477. /*
  478. * Return a duplicate string buffer.
  479. */
  480. const char* dup() const
  481. {
  482. return carla_strdup(fBuffer);
  483. }
  484. // -------------------------------------------------------------------
  485. // public operators
  486. #if 0
  487. operator const char*() const noexcept
  488. {
  489. return fBuffer;
  490. }
  491. #endif
  492. char& operator[](const size_t pos) const noexcept
  493. {
  494. if (pos < fBufferLen)
  495. return fBuffer[pos];
  496. static char fallback;
  497. fallback = '\0';
  498. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  499. return fallback;
  500. }
  501. bool operator==(const char* const strBuf) const noexcept
  502. {
  503. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  504. }
  505. bool operator==(const CarlaString& str) const noexcept
  506. {
  507. return operator==(str.fBuffer);
  508. }
  509. bool operator!=(const char* const strBuf) const noexcept
  510. {
  511. return !operator==(strBuf);
  512. }
  513. bool operator!=(const CarlaString& str) const noexcept
  514. {
  515. return !operator==(str.fBuffer);
  516. }
  517. CarlaString& operator=(const char* const strBuf) noexcept
  518. {
  519. _dup(strBuf);
  520. return *this;
  521. }
  522. CarlaString& operator=(const CarlaString& str) noexcept
  523. {
  524. return operator=(str.fBuffer);
  525. }
  526. CarlaString& operator+=(const char* const strBuf) noexcept
  527. {
  528. if (strBuf == nullptr)
  529. return *this;
  530. const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  531. char newBuf[newBufSize];
  532. std::strcpy(newBuf, fBuffer);
  533. std::strcat(newBuf, strBuf);
  534. _dup(newBuf, newBufSize-1);
  535. return *this;
  536. }
  537. CarlaString& operator+=(const CarlaString& str) noexcept
  538. {
  539. return operator+=(str.fBuffer);
  540. }
  541. CarlaString operator+(const char* const strBuf) noexcept
  542. {
  543. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  544. char newBuf[newBufSize];
  545. std::strcpy(newBuf, fBuffer);
  546. if (strBuf != nullptr)
  547. std::strcat(newBuf, strBuf);
  548. return CarlaString(newBuf);
  549. }
  550. CarlaString operator+(const CarlaString& str) noexcept
  551. {
  552. return operator+(str.fBuffer);
  553. }
  554. // -------------------------------------------------------------------
  555. private:
  556. char* fBuffer; // the actual string buffer
  557. size_t fBufferLen; // string length
  558. /*
  559. * Static null string.
  560. * Prevents excessive allocations for empty strings.
  561. */
  562. static char* _null() noexcept
  563. {
  564. static char sNull = '\0';
  565. return &sNull;
  566. }
  567. /*
  568. * Shared init function.
  569. * Called on all constructors.
  570. */
  571. void _init() noexcept
  572. {
  573. fBuffer = _null();
  574. fBufferLen = 0;
  575. }
  576. /*
  577. * Helper function.
  578. * Called whenever the string needs to be allocated.
  579. *
  580. * Notes:
  581. * - Allocates string only if 'strBuf' is not null and new string contents are different
  582. * - If 'strBuf' is null 'size' must be 0
  583. */
  584. void _dup(const char* const strBuf, const size_t size = 0) noexcept
  585. {
  586. if (strBuf != nullptr)
  587. {
  588. // don't recreate string if contents match
  589. if (std::strcmp(fBuffer, strBuf) == 0)
  590. return;
  591. if (fBuffer != _null())
  592. {
  593. try {
  594. delete[] fBuffer;
  595. } catch(...) {}
  596. }
  597. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  598. try {
  599. fBuffer = new char[fBufferLen+1];
  600. }
  601. catch(...) {
  602. _init();
  603. return;
  604. }
  605. std::strcpy(fBuffer, strBuf);
  606. fBuffer[fBufferLen] = '\0';
  607. }
  608. else
  609. {
  610. CARLA_SAFE_ASSERT(size == 0);
  611. // don't recreate null string
  612. if (fBuffer == _null())
  613. return;
  614. CARLA_SAFE_ASSERT(fBuffer != nullptr);
  615. delete[] fBuffer;
  616. _init();
  617. }
  618. }
  619. CARLA_LEAK_DETECTOR(CarlaString)
  620. CARLA_PREVENT_HEAP_ALLOCATION
  621. };
  622. // -----------------------------------------------------------------------
  623. static inline
  624. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
  625. {
  626. const char* const strBufBefore = strBefore.buffer();
  627. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  628. char newBuf[newBufSize];
  629. std::strcpy(newBuf, strBufBefore);
  630. std::strcat(newBuf, strBufAfter);
  631. return CarlaString(newBuf);
  632. }
  633. static inline
  634. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  635. {
  636. const char* const strBufAfter = strAfter.buffer();
  637. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  638. char newBuf[newBufSize];
  639. std::strcpy(newBuf, strBufBefore);
  640. std::strcat(newBuf, strBufAfter);
  641. return CarlaString(newBuf);
  642. }
  643. // -----------------------------------------------------------------------
  644. #endif // CARLA_STRING_HPP_INCLUDED