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.

732 lines
17KB

  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. std::snprintf(strBuf, 0xff, "%d", value);
  73. strBuf[0xff] = '\0';
  74. _init();
  75. _dup(strBuf);
  76. }
  77. /*
  78. * Unsigned integer, possibly in hexadecimal.
  79. */
  80. explicit CarlaString(const unsigned int value, const bool hexadecimal = false) noexcept
  81. {
  82. char strBuf[0xff+1];
  83. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  84. strBuf[0xff] = '\0';
  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. std::snprintf(strBuf, 0xff, "%ld", value);
  95. strBuf[0xff] = '\0';
  96. _init();
  97. _dup(strBuf);
  98. }
  99. /*
  100. * Long unsigned integer, possibly hexadecimal.
  101. */
  102. explicit CarlaString(const unsigned long value, const bool hexadecimal = false) noexcept
  103. {
  104. char strBuf[0xff+1];
  105. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  106. strBuf[0xff] = '\0';
  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. std::snprintf(strBuf, 0xff, "%lld", value);
  117. strBuf[0xff] = '\0';
  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. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value);
  128. strBuf[0xff] = '\0';
  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. std::snprintf(strBuf, 0xff, "%f", value);
  139. strBuf[0xff] = '\0';
  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. std::snprintf(strBuf, 0xff, "%g", value);
  150. strBuf[0xff] = '\0';
  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. std::free(fBuffer);
  175. fBuffer = nullptr;
  176. fBufferLen = 0;
  177. }
  178. // -------------------------------------------------------------------
  179. // public methods
  180. /*
  181. * Get length of the string.
  182. */
  183. size_t length() const noexcept
  184. {
  185. return fBufferLen;
  186. }
  187. /*
  188. * Check if the string is empty.
  189. */
  190. bool isEmpty() const noexcept
  191. {
  192. return (fBufferLen == 0);
  193. }
  194. /*
  195. * Check if the string is not empty.
  196. */
  197. bool isNotEmpty() const noexcept
  198. {
  199. return (fBufferLen != 0);
  200. }
  201. /*
  202. * Check if the string contains another string, optionally ignoring case.
  203. */
  204. bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
  205. {
  206. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  207. if (ignoreCase)
  208. {
  209. #ifdef __USE_GNU
  210. return (strcasestr(fBuffer, strBuf) != nullptr);
  211. #else
  212. CarlaString tmp1(fBuffer), tmp2(strBuf);
  213. // memory allocation failed or empty string(s)
  214. if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
  215. return false;
  216. tmp1.toLower();
  217. tmp2.toLower();
  218. return (std::strstr(tmp1, tmp2) != nullptr);
  219. #endif
  220. }
  221. return (std::strstr(fBuffer, strBuf) != nullptr);
  222. }
  223. /*
  224. * Overloaded function.
  225. */
  226. bool contains(const CarlaString& str, const bool ignoreCase = false) const noexcept
  227. {
  228. return contains(str.fBuffer, ignoreCase);
  229. }
  230. /*
  231. * Check if character at 'pos' is a digit.
  232. */
  233. bool isDigit(const size_t pos) const noexcept
  234. {
  235. CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
  236. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  237. }
  238. /*
  239. * Check if the string starts with the character 'c'.
  240. */
  241. bool startsWith(const char c) const noexcept
  242. {
  243. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  244. return (fBufferLen > 0 && fBuffer[0] == c);
  245. }
  246. /*
  247. * Check if the string starts with the string 'prefix'.
  248. */
  249. bool startsWith(const char* const prefix) const noexcept
  250. {
  251. CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
  252. const size_t prefixLen(std::strlen(prefix));
  253. if (fBufferLen < prefixLen)
  254. return false;
  255. return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
  256. }
  257. /*
  258. * Check if the string ends with the character 'c'.
  259. */
  260. bool endsWith(const char c) const noexcept
  261. {
  262. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  263. return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
  264. }
  265. /*
  266. * Check if the string ends with the string 'suffix'.
  267. */
  268. bool endsWith(const char* const suffix) const noexcept
  269. {
  270. CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
  271. const size_t suffixLen(std::strlen(suffix));
  272. if (fBufferLen < suffixLen)
  273. return false;
  274. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  275. }
  276. /*
  277. * Find the first occurrence of character 'c' in the string.
  278. * Returns "length()" if the character is not found.
  279. */
  280. size_t find(const char c, bool* const found = nullptr) const noexcept
  281. {
  282. if (fBufferLen == 0 || c == '\0')
  283. {
  284. if (found != nullptr)
  285. *found = false;
  286. return fBufferLen;
  287. }
  288. for (size_t i=0; i < fBufferLen; ++i)
  289. {
  290. if (fBuffer[i] == c)
  291. {
  292. if (found != nullptr)
  293. *found = true;
  294. return i;
  295. }
  296. }
  297. if (found != nullptr)
  298. *found = false;
  299. return fBufferLen;
  300. }
  301. /*
  302. * Find the first occurrence of string 'strBuf' in the string.
  303. * Returns "length()" if the string is not found.
  304. */
  305. size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
  306. {
  307. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  308. {
  309. if (found != nullptr)
  310. *found = false;
  311. return fBufferLen;
  312. }
  313. if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
  314. {
  315. const ssize_t ret(subStrBuf - fBuffer);
  316. if (ret < 0)
  317. {
  318. // should never happen!
  319. carla_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret));
  320. if (found != nullptr)
  321. *found = false;
  322. return fBufferLen;
  323. }
  324. if (found != nullptr)
  325. *found = true;
  326. return static_cast<size_t>(ret);
  327. }
  328. if (found != nullptr)
  329. *found = false;
  330. return fBufferLen;
  331. }
  332. /*
  333. * Find the last occurrence of character 'c' in the string.
  334. * Returns "length()" if the character is not found.
  335. */
  336. size_t rfind(const char c, bool* const found = nullptr) const noexcept
  337. {
  338. if (fBufferLen == 0 || c == '\0')
  339. {
  340. if (found != nullptr)
  341. *found = false;
  342. return fBufferLen;
  343. }
  344. for (size_t i=fBufferLen; i > 0; --i)
  345. {
  346. if (fBuffer[i-1] == c)
  347. {
  348. if (found != nullptr)
  349. *found = true;
  350. return i-1;
  351. }
  352. }
  353. if (found != nullptr)
  354. *found = false;
  355. return fBufferLen;
  356. }
  357. /*
  358. * Find the last occurrence of string 'strBuf' in the string.
  359. * Returns "length()" if the string is not found.
  360. */
  361. size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
  362. {
  363. if (found != nullptr)
  364. *found = false;
  365. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  366. return fBufferLen;
  367. const size_t strBufLen(std::strlen(strBuf));
  368. size_t ret = fBufferLen;
  369. const char* tmpBuf = fBuffer;
  370. for (size_t i=0; i < fBufferLen; ++i)
  371. {
  372. if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
  373. {
  374. if (found != nullptr)
  375. *found = true;
  376. break;
  377. }
  378. --ret;
  379. ++tmpBuf;
  380. }
  381. return fBufferLen-ret;
  382. }
  383. /*
  384. * Clear the string.
  385. */
  386. void clear() noexcept
  387. {
  388. truncate(0);
  389. }
  390. /*
  391. * Replace all occurrences of character 'before' with character 'after'.
  392. */
  393. void replace(const char before, const char after) noexcept
  394. {
  395. CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0',);
  396. for (size_t i=0; i < fBufferLen; ++i)
  397. {
  398. if (fBuffer[i] == before)
  399. fBuffer[i] = after;
  400. }
  401. }
  402. /*
  403. * Truncate the string to size 'n'.
  404. */
  405. void truncate(const size_t n) noexcept
  406. {
  407. if (n >= fBufferLen)
  408. return;
  409. for (size_t i=n; i < fBufferLen; ++i)
  410. fBuffer[i] = '\0';
  411. fBufferLen = n;
  412. }
  413. /*
  414. * Convert all non-basic characters to '_'.
  415. */
  416. void toBasic() noexcept
  417. {
  418. for (size_t i=0; i < fBufferLen; ++i)
  419. {
  420. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  421. continue;
  422. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  423. continue;
  424. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  425. continue;
  426. if (fBuffer[i] == '_')
  427. continue;
  428. fBuffer[i] = '_';
  429. }
  430. }
  431. /*
  432. * Convert to all ascii characters to lowercase.
  433. */
  434. void toLower() noexcept
  435. {
  436. static const char kCharDiff('a' - 'A');
  437. for (size_t i=0; i < fBufferLen; ++i)
  438. {
  439. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  440. fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
  441. }
  442. }
  443. /*
  444. * Convert to all ascii characters to uppercase.
  445. */
  446. void toUpper() noexcept
  447. {
  448. static const char kCharDiff('a' - 'A');
  449. for (size_t i=0; i < fBufferLen; ++i)
  450. {
  451. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  452. fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
  453. }
  454. }
  455. /*
  456. * Direct access to the string buffer (read-only).
  457. */
  458. const char* buffer() const noexcept
  459. {
  460. return fBuffer;
  461. }
  462. /*
  463. * Return a duplicate string buffer.
  464. * May throw.
  465. */
  466. const char* dup() const
  467. {
  468. return carla_strdup(fBuffer);
  469. }
  470. // -------------------------------------------------------------------
  471. // public operators
  472. operator const char*() const noexcept
  473. {
  474. return fBuffer;
  475. }
  476. char& operator[](const size_t pos) const noexcept
  477. {
  478. if (pos < fBufferLen)
  479. return fBuffer[pos];
  480. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  481. static char fallback;
  482. fallback = '\0';
  483. return fallback;
  484. }
  485. bool operator==(const char* const strBuf) const noexcept
  486. {
  487. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  488. }
  489. bool operator!=(const char* const strBuf) const noexcept
  490. {
  491. return !operator==(strBuf);
  492. }
  493. CarlaString& operator=(const char* const strBuf) noexcept
  494. {
  495. _dup(strBuf);
  496. return *this;
  497. }
  498. CarlaString& operator+=(const char* const strBuf) noexcept
  499. {
  500. if (strBuf == nullptr)
  501. return *this;
  502. const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  503. char newBuf[newBufSize];
  504. std::strcpy(newBuf, fBuffer);
  505. std::strcat(newBuf, strBuf);
  506. _dup(newBuf, newBufSize-1);
  507. return *this;
  508. }
  509. CarlaString operator+(const char* const strBuf) noexcept
  510. {
  511. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  512. char newBuf[newBufSize];
  513. std::strcpy(newBuf, fBuffer);
  514. if (strBuf != nullptr)
  515. std::strcat(newBuf, strBuf);
  516. return CarlaString(newBuf);
  517. }
  518. // -------------------------------------------------------------------
  519. private:
  520. char* fBuffer; // the actual string buffer
  521. size_t fBufferLen; // string length
  522. /*
  523. * Static null string.
  524. * Prevents excessive allocations for empty strings.
  525. */
  526. static char* _null() noexcept
  527. {
  528. static char sNull = '\0';
  529. return &sNull;
  530. }
  531. /*
  532. * Shared init function.
  533. * Called on all constructors.
  534. */
  535. void _init() noexcept
  536. {
  537. fBuffer = _null();
  538. fBufferLen = 0;
  539. }
  540. /*
  541. * Helper function.
  542. * Called whenever the string needs to be allocated.
  543. *
  544. * Notes:
  545. * - Allocates string only if 'strBuf' is not null and new string contents are different
  546. * - If 'strBuf' is null, 'size' must be 0
  547. */
  548. void _dup(const char* const strBuf, const size_t size = 0) noexcept
  549. {
  550. if (strBuf != nullptr)
  551. {
  552. // don't recreate string if contents match
  553. if (std::strcmp(fBuffer, strBuf) == 0)
  554. return;
  555. if (fBuffer != _null())
  556. std::free(fBuffer);
  557. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  558. fBuffer = (char*)std::malloc(fBufferLen+1);
  559. if (fBuffer == nullptr)
  560. return _init();
  561. std::strcpy(fBuffer, strBuf);
  562. fBuffer[fBufferLen] = '\0';
  563. }
  564. else
  565. {
  566. CARLA_SAFE_ASSERT(size == 0);
  567. // don't recreate null string
  568. if (fBuffer == _null())
  569. return;
  570. CARLA_SAFE_ASSERT(fBuffer != nullptr);
  571. std::free(fBuffer);
  572. _init();
  573. }
  574. }
  575. CARLA_LEAK_DETECTOR(CarlaString)
  576. CARLA_PREVENT_HEAP_ALLOCATION
  577. };
  578. // -----------------------------------------------------------------------
  579. static inline
  580. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
  581. {
  582. const char* const strBufBefore = strBefore.buffer();
  583. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  584. char newBuf[newBufSize];
  585. std::strcpy(newBuf, strBufBefore);
  586. std::strcat(newBuf, strBufAfter);
  587. return CarlaString(newBuf);
  588. }
  589. static inline
  590. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  591. {
  592. const char* const strBufAfter = strAfter.buffer();
  593. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  594. char newBuf[newBufSize];
  595. std::strcpy(newBuf, strBufBefore);
  596. std::strcat(newBuf, strBufAfter);
  597. return CarlaString(newBuf);
  598. }
  599. // -----------------------------------------------------------------------
  600. #endif // CARLA_STRING_HPP_INCLUDED