The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

511 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_StringArray.h"
  21. //==============================================================================
  22. StringArray::StringArray() throw()
  23. {
  24. }
  25. StringArray::StringArray (const StringArray& other)
  26. : strings (other.strings)
  27. {
  28. }
  29. StringArray::StringArray (const String& firstValue)
  30. {
  31. strings.add (firstValue);
  32. }
  33. StringArray::StringArray (const juce_wchar* const* const initialStrings,
  34. const int numberOfStrings)
  35. {
  36. for (int i = 0; i < numberOfStrings; ++i)
  37. strings.add (initialStrings [i]);
  38. }
  39. StringArray::StringArray (const char* const* const initialStrings,
  40. const int numberOfStrings)
  41. {
  42. for (int i = 0; i < numberOfStrings; ++i)
  43. strings.add (initialStrings [i]);
  44. }
  45. StringArray::StringArray (const juce_wchar* const* const initialStrings)
  46. {
  47. int i = 0;
  48. while (initialStrings[i] != 0)
  49. strings.add (initialStrings [i++]);
  50. }
  51. StringArray::StringArray (const char* const* const initialStrings)
  52. {
  53. int i = 0;
  54. while (initialStrings[i] != 0)
  55. strings.add (initialStrings [i++]);
  56. }
  57. StringArray& StringArray::operator= (const StringArray& other)
  58. {
  59. strings = other.strings;
  60. return *this;
  61. }
  62. StringArray::~StringArray()
  63. {
  64. }
  65. bool StringArray::operator== (const StringArray& other) const throw()
  66. {
  67. if (other.size() != size())
  68. return false;
  69. for (int i = size(); --i >= 0;)
  70. if (other.strings.getReference(i) != strings.getReference(i))
  71. return false;
  72. return true;
  73. }
  74. bool StringArray::operator!= (const StringArray& other) const throw()
  75. {
  76. return ! operator== (other);
  77. }
  78. void StringArray::clear()
  79. {
  80. strings.clear();
  81. }
  82. const String& StringArray::operator[] (const int index) const throw()
  83. {
  84. if (((unsigned int) index) < (unsigned int) strings.size())
  85. return strings.getReference (index);
  86. return String::empty;
  87. }
  88. String& StringArray::getReference (const int index) throw()
  89. {
  90. jassert (((unsigned int) index) < (unsigned int) strings.size());
  91. return strings.getReference (index);
  92. }
  93. void StringArray::add (const String& newString)
  94. {
  95. strings.add (newString);
  96. }
  97. void StringArray::insert (const int index, const String& newString)
  98. {
  99. strings.insert (index, newString);
  100. }
  101. void StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase)
  102. {
  103. if (! contains (newString, ignoreCase))
  104. add (newString);
  105. }
  106. void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
  107. {
  108. if (startIndex < 0)
  109. {
  110. jassertfalse;
  111. startIndex = 0;
  112. }
  113. if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size())
  114. numElementsToAdd = otherArray.size() - startIndex;
  115. while (--numElementsToAdd >= 0)
  116. strings.add (otherArray.strings.getReference (startIndex++));
  117. }
  118. void StringArray::set (const int index, const String& newString)
  119. {
  120. strings.set (index, newString);
  121. }
  122. bool StringArray::contains (const String& stringToLookFor, const bool ignoreCase) const
  123. {
  124. if (ignoreCase)
  125. {
  126. for (int i = size(); --i >= 0;)
  127. if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
  128. return true;
  129. }
  130. else
  131. {
  132. for (int i = size(); --i >= 0;)
  133. if (stringToLookFor == strings.getReference(i))
  134. return true;
  135. }
  136. return false;
  137. }
  138. int StringArray::indexOf (const String& stringToLookFor, const bool ignoreCase, int i) const
  139. {
  140. if (i < 0)
  141. i = 0;
  142. const int numElements = size();
  143. if (ignoreCase)
  144. {
  145. while (i < numElements)
  146. {
  147. if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
  148. return i;
  149. ++i;
  150. }
  151. }
  152. else
  153. {
  154. while (i < numElements)
  155. {
  156. if (stringToLookFor == strings.getReference (i))
  157. return i;
  158. ++i;
  159. }
  160. }
  161. return -1;
  162. }
  163. //==============================================================================
  164. void StringArray::remove (const int index)
  165. {
  166. strings.remove (index);
  167. }
  168. void StringArray::removeString (const String& stringToRemove,
  169. const bool ignoreCase)
  170. {
  171. if (ignoreCase)
  172. {
  173. for (int i = size(); --i >= 0;)
  174. if (strings.getReference(i).equalsIgnoreCase (stringToRemove))
  175. strings.remove (i);
  176. }
  177. else
  178. {
  179. for (int i = size(); --i >= 0;)
  180. if (stringToRemove == strings.getReference (i))
  181. strings.remove (i);
  182. }
  183. }
  184. void StringArray::removeRange (int startIndex, int numberToRemove)
  185. {
  186. strings.removeRange (startIndex, numberToRemove);
  187. }
  188. //==============================================================================
  189. void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings)
  190. {
  191. if (removeWhitespaceStrings)
  192. {
  193. for (int i = size(); --i >= 0;)
  194. if (! strings.getReference(i).containsNonWhitespaceChars())
  195. strings.remove (i);
  196. }
  197. else
  198. {
  199. for (int i = size(); --i >= 0;)
  200. if (strings.getReference(i).isEmpty())
  201. strings.remove (i);
  202. }
  203. }
  204. void StringArray::trim()
  205. {
  206. for (int i = size(); --i >= 0;)
  207. {
  208. String& s = strings.getReference(i);
  209. s = s.trim();
  210. }
  211. }
  212. //==============================================================================
  213. class InternalStringArrayComparator_CaseSensitive
  214. {
  215. public:
  216. static int compareElements (String& first, String& second) { return first.compare (second); }
  217. };
  218. class InternalStringArrayComparator_CaseInsensitive
  219. {
  220. public:
  221. static int compareElements (String& first, String& second) { return first.compareIgnoreCase (second); }
  222. };
  223. void StringArray::sort (const bool ignoreCase)
  224. {
  225. if (ignoreCase)
  226. {
  227. InternalStringArrayComparator_CaseInsensitive comp;
  228. strings.sort (comp);
  229. }
  230. else
  231. {
  232. InternalStringArrayComparator_CaseSensitive comp;
  233. strings.sort (comp);
  234. }
  235. }
  236. void StringArray::move (const int currentIndex, int newIndex) throw()
  237. {
  238. strings.move (currentIndex, newIndex);
  239. }
  240. //==============================================================================
  241. const String StringArray::joinIntoString (const String& separator, int start, int numberToJoin) const
  242. {
  243. const int last = (numberToJoin < 0) ? size()
  244. : jmin (size(), start + numberToJoin);
  245. if (start < 0)
  246. start = 0;
  247. if (start >= last)
  248. return String::empty;
  249. if (start == last - 1)
  250. return strings.getReference (start);
  251. const int separatorLen = separator.length();
  252. int charsNeeded = separatorLen * (last - start - 1);
  253. for (int i = start; i < last; ++i)
  254. charsNeeded += strings.getReference(i).length();
  255. String result;
  256. result.preallocateStorage (charsNeeded);
  257. juce_wchar* dest = result;
  258. while (start < last)
  259. {
  260. const String& s = strings.getReference (start);
  261. const int len = s.length();
  262. if (len > 0)
  263. {
  264. s.copyToUnicode (dest, len);
  265. dest += len;
  266. }
  267. if (++start < last && separatorLen > 0)
  268. {
  269. separator.copyToUnicode (dest, separatorLen);
  270. dest += separatorLen;
  271. }
  272. }
  273. *dest = 0;
  274. return result;
  275. }
  276. int StringArray::addTokens (const String& text, const bool preserveQuotedStrings)
  277. {
  278. return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : "");
  279. }
  280. int StringArray::addTokens (const String& text, const String& breakCharacters, const String& quoteCharacters)
  281. {
  282. int num = 0;
  283. if (text.isNotEmpty())
  284. {
  285. bool insideQuotes = false;
  286. juce_wchar currentQuoteChar = 0;
  287. int i = 0;
  288. int tokenStart = 0;
  289. for (;;)
  290. {
  291. const juce_wchar c = text[i];
  292. const bool isBreak = (c == 0) || ((! insideQuotes) && breakCharacters.containsChar (c));
  293. if (! isBreak)
  294. {
  295. if (quoteCharacters.containsChar (c))
  296. {
  297. if (insideQuotes)
  298. {
  299. // only break out of quotes-mode if we find a matching quote to the
  300. // one that we opened with..
  301. if (currentQuoteChar == c)
  302. insideQuotes = false;
  303. }
  304. else
  305. {
  306. insideQuotes = true;
  307. currentQuoteChar = c;
  308. }
  309. }
  310. }
  311. else
  312. {
  313. add (String (static_cast <const juce_wchar*> (text) + tokenStart, i - tokenStart));
  314. ++num;
  315. tokenStart = i + 1;
  316. }
  317. if (c == 0)
  318. break;
  319. ++i;
  320. }
  321. }
  322. return num;
  323. }
  324. int StringArray::addLines (const String& sourceText)
  325. {
  326. int numLines = 0;
  327. const juce_wchar* text = sourceText;
  328. while (*text != 0)
  329. {
  330. const juce_wchar* const startOfLine = text;
  331. while (*text != 0)
  332. {
  333. if (*text == '\r')
  334. {
  335. ++text;
  336. if (*text == '\n')
  337. ++text;
  338. break;
  339. }
  340. if (*text == '\n')
  341. {
  342. ++text;
  343. break;
  344. }
  345. ++text;
  346. }
  347. const juce_wchar* endOfLine = text;
  348. if (endOfLine > startOfLine && (*(endOfLine - 1) == '\r' || *(endOfLine - 1) == '\n'))
  349. --endOfLine;
  350. if (endOfLine > startOfLine && (*(endOfLine - 1) == '\r' || *(endOfLine - 1) == '\n'))
  351. --endOfLine;
  352. add (String (startOfLine, jmax (0, (int) (endOfLine - startOfLine))));
  353. ++numLines;
  354. }
  355. return numLines;
  356. }
  357. //==============================================================================
  358. void StringArray::removeDuplicates (const bool ignoreCase)
  359. {
  360. for (int i = 0; i < size() - 1; ++i)
  361. {
  362. const String s (strings.getReference(i));
  363. int nextIndex = i + 1;
  364. for (;;)
  365. {
  366. nextIndex = indexOf (s, ignoreCase, nextIndex);
  367. if (nextIndex < 0)
  368. break;
  369. strings.remove (nextIndex);
  370. }
  371. }
  372. }
  373. void StringArray::appendNumbersToDuplicates (const bool ignoreCase,
  374. const bool appendNumberToFirstInstance,
  375. const juce_wchar* preNumberString,
  376. const juce_wchar* postNumberString)
  377. {
  378. if (preNumberString == 0)
  379. preNumberString = L" (";
  380. if (postNumberString == 0)
  381. postNumberString = L")";
  382. for (int i = 0; i < size() - 1; ++i)
  383. {
  384. String& s = strings.getReference(i);
  385. int nextIndex = indexOf (s, ignoreCase, i + 1);
  386. if (nextIndex >= 0)
  387. {
  388. const String original (s);
  389. int number = 0;
  390. if (appendNumberToFirstInstance)
  391. s = original + preNumberString + String (++number) + postNumberString;
  392. else
  393. ++number;
  394. while (nextIndex >= 0)
  395. {
  396. set (nextIndex, (*this)[nextIndex] + preNumberString + String (++number) + postNumberString);
  397. nextIndex = indexOf (original, ignoreCase, nextIndex + 1);
  398. }
  399. }
  400. }
  401. }
  402. void StringArray::minimiseStorageOverheads()
  403. {
  404. strings.minimiseStorageOverheads();
  405. }
  406. END_JUCE_NAMESPACE