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.

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