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.

863 lines
21KB

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