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.

491 lines
11KB

  1. /*
  2. * Carla String
  3. * Copyright (C) 2013 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 GPL.txt file
  16. */
  17. #ifndef __CARLA_STRING_HPP__
  18. #define __CARLA_STRING_HPP__
  19. #include "CarlaJuceUtils.hpp"
  20. // -------------------------------------------------
  21. // CarlaString class
  22. class CarlaString
  23. {
  24. public:
  25. // ---------------------------------------------
  26. // constructors (no explicit conversions allowed)
  27. explicit CarlaString()
  28. {
  29. _init();
  30. _dup(nullptr);
  31. }
  32. explicit CarlaString(char* const strBuf)
  33. {
  34. _init();
  35. _dup(strBuf);
  36. }
  37. explicit CarlaString(const char* const strBuf)
  38. {
  39. _init();
  40. _dup(strBuf);
  41. }
  42. explicit CarlaString(const int value)
  43. {
  44. char strBuf[0xff] = { '\0' };
  45. std::snprintf(strBuf, 0xff, "%d", value);
  46. _init();
  47. _dup(strBuf);
  48. }
  49. explicit CarlaString(const unsigned int value, const bool hexadecimal = false)
  50. {
  51. char strBuf[0xff] = { '\0' };
  52. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  53. _init();
  54. _dup(strBuf);
  55. }
  56. explicit CarlaString(const long int value)
  57. {
  58. char strBuf[0xff] = { '\0' };
  59. std::snprintf(strBuf, 0xff, "%ld", value);
  60. _init();
  61. _dup(strBuf);
  62. }
  63. explicit CarlaString(const unsigned long int value, const bool hexadecimal = false)
  64. {
  65. char strBuf[0xff] = { '\0' };
  66. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  67. _init();
  68. _dup(strBuf);
  69. }
  70. explicit CarlaString(const float value)
  71. {
  72. char strBuf[0xff] = { '\0' };
  73. std::snprintf(strBuf, 0xff, "%f", value);
  74. _init();
  75. _dup(strBuf);
  76. }
  77. explicit CarlaString(const double value)
  78. {
  79. char strBuf[0xff] = { '\0' };
  80. std::snprintf(strBuf, 0xff, "%g", value);
  81. _init();
  82. _dup(strBuf);
  83. }
  84. // ---------------------------------------------
  85. // non-explicit constructor
  86. CarlaString(const CarlaString& str)
  87. {
  88. _init();
  89. _dup(str.buffer);
  90. }
  91. // ---------------------------------------------
  92. // destructor
  93. ~CarlaString()
  94. {
  95. CARLA_ASSERT(buffer != nullptr);
  96. delete[] buffer;
  97. buffer = nullptr;
  98. }
  99. // ---------------------------------------------
  100. // public methods
  101. size_t length() const
  102. {
  103. return bufferLen;
  104. }
  105. bool isEmpty() const
  106. {
  107. return (bufferLen == 0);
  108. }
  109. bool isNotEmpty() const
  110. {
  111. return (bufferLen != 0);
  112. }
  113. #ifdef __USE_GNU
  114. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  115. {
  116. if (strBuf == nullptr)
  117. return false;
  118. if (ignoreCase)
  119. return (strcasestr(buffer, strBuf) != nullptr);
  120. else
  121. return (std::strstr(buffer, strBuf) != nullptr);
  122. }
  123. bool contains(const CarlaString& str, const bool ignoreCase = false) const
  124. {
  125. return contains(str.buffer, ignoreCase);
  126. }
  127. #else
  128. bool contains(const char* const strBuf) const
  129. {
  130. if (strBuf == nullptr)
  131. return false;
  132. return (std::strstr(buffer, strBuf) != nullptr);
  133. }
  134. bool contains(const CarlaString& str) const
  135. {
  136. return contains(str.buffer);
  137. }
  138. #endif
  139. bool isDigit(const size_t pos) const
  140. {
  141. if (pos >= bufferLen)
  142. return false;
  143. return (buffer[pos] >= '0' && buffer[pos] <= '9');
  144. }
  145. bool startsWith(const char* const prefix) const
  146. {
  147. if (prefix == nullptr)
  148. return false;
  149. const size_t prefixLen(std::strlen(prefix));
  150. if (bufferLen < prefixLen)
  151. return false;
  152. return (std::strncmp(buffer + (bufferLen-prefixLen), prefix, prefixLen) == 0);
  153. }
  154. bool endsWith(const char* const suffix) const
  155. {
  156. if (suffix == nullptr)
  157. return false;
  158. const size_t suffixLen(std::strlen(suffix));
  159. if (bufferLen < suffixLen)
  160. return false;
  161. return (std::strncmp(buffer + (bufferLen-suffixLen), suffix, suffixLen) == 0);
  162. }
  163. void clear()
  164. {
  165. truncate(0);
  166. }
  167. size_t find(const char c) const
  168. {
  169. for (size_t i=0; i < bufferLen; ++i)
  170. {
  171. if (buffer[i] == c)
  172. return i;
  173. }
  174. return 0;
  175. }
  176. size_t rfind(const char c) const
  177. {
  178. for (size_t i=bufferLen; i > 0; --i)
  179. {
  180. if (buffer[i-1] == c)
  181. return i-1;
  182. }
  183. return 0;
  184. }
  185. size_t rfind(const char* const strBuf) const
  186. {
  187. if (strBuf == nullptr || strBuf[0] == '\0')
  188. return bufferLen;
  189. size_t ret = bufferLen+1;
  190. const char* tmpBuf = buffer;
  191. for (size_t i=0; i < bufferLen; ++i)
  192. {
  193. if (std::strstr(tmpBuf, strBuf) == nullptr)
  194. break;
  195. --ret;
  196. ++tmpBuf;
  197. }
  198. return (ret > bufferLen) ? bufferLen : bufferLen-ret;
  199. }
  200. void replace(const char before, const char after)
  201. {
  202. if (after == '\0')
  203. return;
  204. for (size_t i=0; i < bufferLen; ++i)
  205. {
  206. if (buffer[i] == before)
  207. buffer[i] = after;
  208. else if (buffer[i] == '\0')
  209. break;
  210. }
  211. }
  212. void truncate(const size_t n)
  213. {
  214. if (n >= bufferLen)
  215. return;
  216. for (size_t i=n; i < bufferLen; ++i)
  217. buffer[i] = '\0';
  218. bufferLen = n;
  219. }
  220. void toBasic()
  221. {
  222. for (size_t i=0; i < bufferLen; ++i)
  223. {
  224. if (buffer[i] >= '0' && buffer[i] <= '9')
  225. continue;
  226. if (buffer[i] >= 'A' && buffer[i] <= 'Z')
  227. continue;
  228. if (buffer[i] >= 'a' && buffer[i] <= 'z')
  229. continue;
  230. if (buffer[i] == '_')
  231. continue;
  232. buffer[i] = '_';
  233. }
  234. }
  235. void toLower()
  236. {
  237. static const char kCharDiff = 'a' - 'A';
  238. for (size_t i=0; i < bufferLen; ++i)
  239. {
  240. if (buffer[i] >= 'A' && buffer[i] <= 'Z')
  241. buffer[i] += kCharDiff;
  242. }
  243. }
  244. void toUpper()
  245. {
  246. static const char kCharDiff = 'a' - 'A';
  247. for (size_t i=0; i < bufferLen; ++i)
  248. {
  249. if (buffer[i] >= 'a' && buffer[i] <= 'z')
  250. buffer[i] -= kCharDiff;
  251. }
  252. }
  253. // ---------------------------------------------
  254. // public operators
  255. operator const char*() const
  256. {
  257. return buffer;
  258. }
  259. char& operator[](const size_t pos)
  260. {
  261. return buffer[pos];
  262. }
  263. bool operator==(const char* const strBuf) const
  264. {
  265. return (strBuf != nullptr && std::strcmp(buffer, strBuf) == 0);
  266. }
  267. bool operator==(const CarlaString& str) const
  268. {
  269. return operator==(str.buffer);
  270. }
  271. bool operator!=(const char* const strBuf) const
  272. {
  273. return !operator==(strBuf);
  274. }
  275. bool operator!=(const CarlaString& str) const
  276. {
  277. return !operator==(str.buffer);
  278. }
  279. CarlaString& operator=(const char* const strBuf)
  280. {
  281. _dup(strBuf);
  282. return *this;
  283. }
  284. CarlaString& operator=(const CarlaString& str)
  285. {
  286. return operator=(str.buffer);
  287. }
  288. CarlaString& operator+=(const char* const strBuf)
  289. {
  290. const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  291. char newBuf[newBufSize];
  292. std::strcpy(newBuf, buffer);
  293. std::strcat(newBuf, strBuf);
  294. _dup(newBuf, newBufSize-1);
  295. return *this;
  296. }
  297. CarlaString& operator+=(const CarlaString& str)
  298. {
  299. return operator+=(str.buffer);
  300. }
  301. CarlaString operator+(const char* const strBuf)
  302. {
  303. const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  304. char newBuf[newBufSize];
  305. std::strcpy(newBuf, buffer);
  306. std::strcat(newBuf, strBuf);
  307. return CarlaString(newBuf);
  308. }
  309. CarlaString operator+(const CarlaString& str)
  310. {
  311. return operator+(str.buffer);
  312. }
  313. // ---------------------------------------------
  314. private:
  315. char* buffer;
  316. size_t bufferLen;
  317. bool firstInit;
  318. void _init()
  319. {
  320. buffer = nullptr;
  321. bufferLen = 0;
  322. firstInit = true;
  323. }
  324. // allocate string strBuf if not null
  325. // size > 0 only if strBuf is valid
  326. void _dup(const char* const strBuf, const size_t size = 0)
  327. {
  328. if (strBuf != nullptr)
  329. {
  330. // don't recreate string if contents match
  331. if (firstInit || std::strcmp(buffer, strBuf) != 0)
  332. {
  333. if (! firstInit)
  334. {
  335. CARLA_ASSERT(buffer != nullptr);
  336. delete[] buffer;
  337. }
  338. bufferLen = (size > 0) ? size : std::strlen(strBuf);
  339. buffer = new char[bufferLen+1];
  340. std::strcpy(buffer, strBuf);
  341. buffer[bufferLen] = '\0';
  342. firstInit = false;
  343. }
  344. }
  345. else
  346. {
  347. CARLA_ASSERT(size == 0);
  348. // don't recreate null string
  349. if (firstInit || bufferLen != 0)
  350. {
  351. if (! firstInit)
  352. {
  353. CARLA_ASSERT(buffer != nullptr);
  354. delete[] buffer;
  355. }
  356. bufferLen = 0;
  357. buffer = new char[1];
  358. buffer[0] = '\0';
  359. firstInit = false;
  360. }
  361. }
  362. }
  363. CARLA_LEAK_DETECTOR(CarlaString)
  364. CARLA_PREVENT_HEAP_ALLOCATION
  365. };
  366. static inline
  367. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter)
  368. {
  369. const char* const strBufBefore = (const char*)strBefore;
  370. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  371. char newBuf[newBufSize];
  372. std::strcpy(newBuf, strBufBefore);
  373. std::strcat(newBuf, strBufAfter);
  374. return CarlaString(newBuf);
  375. }
  376. static inline
  377. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter)
  378. {
  379. const char* const strBufAfter = (const char*)strAfter;
  380. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  381. char newBuf[newBufSize];
  382. std::strcpy(newBuf, strBufBefore);
  383. std::strcat(newBuf, strBufAfter);
  384. return CarlaString(newBuf);
  385. }
  386. // -------------------------------------------------
  387. #endif // __CARLA_UTILS_HPP__