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.

485 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. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  114. {
  115. if (strBuf == nullptr)
  116. return false;
  117. if (ignoreCase)
  118. {
  119. #ifdef __USE_GNU
  120. return (strcasestr(buffer, strBuf) != nullptr);
  121. #else
  122. CarlaString tmp1(buffer), tmp2(strBuf);
  123. tmp1.toLower();
  124. tmp2.toLower();
  125. return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr);
  126. #endif
  127. }
  128. return (std::strstr(buffer, strBuf) != nullptr);
  129. }
  130. bool contains(const CarlaString& str, const bool ignoreCase = false) const
  131. {
  132. return contains(str.buffer, ignoreCase);
  133. }
  134. bool isDigit(const size_t pos) const
  135. {
  136. if (pos >= bufferLen)
  137. return false;
  138. return (buffer[pos] >= '0' && buffer[pos] <= '9');
  139. }
  140. bool startsWith(const char* const prefix) const
  141. {
  142. if (prefix == nullptr)
  143. return false;
  144. const size_t prefixLen(std::strlen(prefix));
  145. if (bufferLen < prefixLen)
  146. return false;
  147. return (std::strncmp(buffer + (bufferLen-prefixLen), prefix, prefixLen) == 0);
  148. }
  149. bool endsWith(const char* const suffix) const
  150. {
  151. if (suffix == nullptr)
  152. return false;
  153. const size_t suffixLen(std::strlen(suffix));
  154. if (bufferLen < suffixLen)
  155. return false;
  156. return (std::strncmp(buffer + (bufferLen-suffixLen), suffix, suffixLen) == 0);
  157. }
  158. void clear()
  159. {
  160. truncate(0);
  161. }
  162. size_t find(const char c) const
  163. {
  164. for (size_t i=0; i < bufferLen; ++i)
  165. {
  166. if (buffer[i] == c)
  167. return i;
  168. }
  169. return 0;
  170. }
  171. size_t rfind(const char c) const
  172. {
  173. for (size_t i=bufferLen; i > 0; --i)
  174. {
  175. if (buffer[i-1] == c)
  176. return i-1;
  177. }
  178. return 0;
  179. }
  180. size_t rfind(const char* const strBuf) const
  181. {
  182. if (strBuf == nullptr || strBuf[0] == '\0')
  183. return bufferLen;
  184. size_t ret = bufferLen+1;
  185. const char* tmpBuf = buffer;
  186. for (size_t i=0; i < bufferLen; ++i)
  187. {
  188. if (std::strstr(tmpBuf, strBuf) == nullptr)
  189. break;
  190. --ret;
  191. ++tmpBuf;
  192. }
  193. return (ret > bufferLen) ? bufferLen : bufferLen-ret;
  194. }
  195. void replace(const char before, const char after)
  196. {
  197. if (after == '\0')
  198. return;
  199. for (size_t i=0; i < bufferLen; ++i)
  200. {
  201. if (buffer[i] == before)
  202. buffer[i] = after;
  203. else if (buffer[i] == '\0')
  204. break;
  205. }
  206. }
  207. void truncate(const size_t n)
  208. {
  209. if (n >= bufferLen)
  210. return;
  211. for (size_t i=n; i < bufferLen; ++i)
  212. buffer[i] = '\0';
  213. bufferLen = n;
  214. }
  215. void toBasic()
  216. {
  217. for (size_t i=0; i < bufferLen; ++i)
  218. {
  219. if (buffer[i] >= '0' && buffer[i] <= '9')
  220. continue;
  221. if (buffer[i] >= 'A' && buffer[i] <= 'Z')
  222. continue;
  223. if (buffer[i] >= 'a' && buffer[i] <= 'z')
  224. continue;
  225. if (buffer[i] == '_')
  226. continue;
  227. buffer[i] = '_';
  228. }
  229. }
  230. void toLower()
  231. {
  232. static const char kCharDiff = 'a' - 'A';
  233. for (size_t i=0; i < bufferLen; ++i)
  234. {
  235. if (buffer[i] >= 'A' && buffer[i] <= 'Z')
  236. buffer[i] += kCharDiff;
  237. }
  238. }
  239. void toUpper()
  240. {
  241. static const char kCharDiff = 'a' - 'A';
  242. for (size_t i=0; i < bufferLen; ++i)
  243. {
  244. if (buffer[i] >= 'a' && buffer[i] <= 'z')
  245. buffer[i] -= kCharDiff;
  246. }
  247. }
  248. // ---------------------------------------------
  249. // public operators
  250. operator const char*() const
  251. {
  252. return buffer;
  253. }
  254. char& operator[](const size_t pos)
  255. {
  256. return buffer[pos];
  257. }
  258. bool operator==(const char* const strBuf) const
  259. {
  260. return (strBuf != nullptr && std::strcmp(buffer, strBuf) == 0);
  261. }
  262. bool operator==(const CarlaString& str) const
  263. {
  264. return operator==(str.buffer);
  265. }
  266. bool operator!=(const char* const strBuf) const
  267. {
  268. return !operator==(strBuf);
  269. }
  270. bool operator!=(const CarlaString& str) const
  271. {
  272. return !operator==(str.buffer);
  273. }
  274. CarlaString& operator=(const char* const strBuf)
  275. {
  276. _dup(strBuf);
  277. return *this;
  278. }
  279. CarlaString& operator=(const CarlaString& str)
  280. {
  281. return operator=(str.buffer);
  282. }
  283. CarlaString& operator+=(const char* const strBuf)
  284. {
  285. const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  286. char newBuf[newBufSize];
  287. std::strcpy(newBuf, buffer);
  288. std::strcat(newBuf, strBuf);
  289. _dup(newBuf, newBufSize-1);
  290. return *this;
  291. }
  292. CarlaString& operator+=(const CarlaString& str)
  293. {
  294. return operator+=(str.buffer);
  295. }
  296. CarlaString operator+(const char* const strBuf)
  297. {
  298. const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  299. char newBuf[newBufSize];
  300. std::strcpy(newBuf, buffer);
  301. std::strcat(newBuf, strBuf);
  302. return CarlaString(newBuf);
  303. }
  304. CarlaString operator+(const CarlaString& str)
  305. {
  306. return operator+(str.buffer);
  307. }
  308. // ---------------------------------------------
  309. private:
  310. char* buffer;
  311. size_t bufferLen;
  312. bool firstInit;
  313. void _init()
  314. {
  315. buffer = nullptr;
  316. bufferLen = 0;
  317. firstInit = true;
  318. }
  319. // allocate string strBuf if not null
  320. // size > 0 only if strBuf is valid
  321. void _dup(const char* const strBuf, const size_t size = 0)
  322. {
  323. if (strBuf != nullptr)
  324. {
  325. // don't recreate string if contents match
  326. if (firstInit || std::strcmp(buffer, strBuf) != 0)
  327. {
  328. if (! firstInit)
  329. {
  330. CARLA_ASSERT(buffer != nullptr);
  331. delete[] buffer;
  332. }
  333. bufferLen = (size > 0) ? size : std::strlen(strBuf);
  334. buffer = new char[bufferLen+1];
  335. std::strcpy(buffer, strBuf);
  336. buffer[bufferLen] = '\0';
  337. firstInit = false;
  338. }
  339. }
  340. else
  341. {
  342. CARLA_ASSERT(size == 0);
  343. // don't recreate null string
  344. if (firstInit || bufferLen != 0)
  345. {
  346. if (! firstInit)
  347. {
  348. CARLA_ASSERT(buffer != nullptr);
  349. delete[] buffer;
  350. }
  351. bufferLen = 0;
  352. buffer = new char[1];
  353. buffer[0] = '\0';
  354. firstInit = false;
  355. }
  356. }
  357. }
  358. CARLA_LEAK_DETECTOR(CarlaString)
  359. CARLA_PREVENT_HEAP_ALLOCATION
  360. };
  361. static inline
  362. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter)
  363. {
  364. const char* const strBufBefore = (const char*)strBefore;
  365. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  366. char newBuf[newBufSize];
  367. std::strcpy(newBuf, strBufBefore);
  368. std::strcat(newBuf, strBufAfter);
  369. return CarlaString(newBuf);
  370. }
  371. static inline
  372. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter)
  373. {
  374. const char* const strBufAfter = (const char*)strAfter;
  375. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  376. char newBuf[newBufSize];
  377. std::strcpy(newBuf, strBufBefore);
  378. std::strcat(newBuf, strBufAfter);
  379. return CarlaString(newBuf);
  380. }
  381. // -------------------------------------------------
  382. #endif // __CARLA_UTILS_HPP__