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.

496 lines
13KB

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