PageRenderTime 59ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libs/utils/filesearch.cpp

https://github.com/khangbotics/qgroundcontrol
C++ | 260 lines | 204 code | 26 blank | 30 comment | 62 complexity | 6b3244e87d248251ef98a31777757064 MD5 | raw file
  1. /**
  2. ******************************************************************************
  3. *
  4. * @file filesearch.cpp
  5. * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
  6. * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009.
  7. * @brief
  8. * @see The GNU Public License (GPL) Version 3
  9. * @defgroup
  10. * @{
  11. *
  12. *****************************************************************************/
  13. /*
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 3 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful, but
  20. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  21. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  22. * for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License along
  25. * with this program; if not, write to the Free Software Foundation, Inc.,
  26. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. */
  28. #include "filesearch.h"
  29. #include <cctype>
  30. #include <QtCore/QIODevice>
  31. #include <QtCore/QBuffer>
  32. #include <QtCore/QFile>
  33. #include <QtCore/QFutureInterface>
  34. #include <QtCore/QtConcurrentRun>
  35. #include <QtCore/QRegExp>
  36. #include <QtCore/QCoreApplication>
  37. #include <qtconcurrent/runextensions.h>
  38. using namespace Utils;
  39. static inline QString msgCanceled(const QString &searchTerm, int numMatches, int numFilesSearched)
  40. {
  41. return QCoreApplication::translate("Utils::FileSearch",
  42. "%1: canceled. %n occurrences found in %2 files.",
  43. 0, QCoreApplication::CodecForTr, numMatches).
  44. arg(searchTerm).arg(numFilesSearched);
  45. }
  46. static inline QString msgFound(const QString &searchTerm, int numMatches, int numFilesSearched)
  47. {
  48. return QCoreApplication::translate("Utils::FileSearch",
  49. "%1: %n occurrences found in %2 files.",
  50. 0, QCoreApplication::CodecForTr, numMatches).
  51. arg(searchTerm).arg(numFilesSearched);
  52. }
  53. static inline QString msgFound(const QString &searchTerm, int numMatches, int numFilesSearched, int filesSize)
  54. {
  55. return QCoreApplication::translate("Utils::FileSearch",
  56. "%1: %n occurrences found in %2 of %3 files.",
  57. 0, QCoreApplication::CodecForTr, numMatches).
  58. arg(searchTerm).arg(numFilesSearched).arg(filesSize);
  59. }
  60. namespace {
  61. void runFileSearch(QFutureInterface<FileSearchResult> &future,
  62. QString searchTerm,
  63. QStringList files,
  64. QTextDocument::FindFlags flags,
  65. QMap<QString, QString> fileToContentsMap)
  66. {
  67. future.setProgressRange(0, files.size());
  68. int numFilesSearched = 0;
  69. int numMatches = 0;
  70. bool caseInsensitive = !(flags & QTextDocument::FindCaseSensitively);
  71. bool wholeWord = (flags & QTextDocument::FindWholeWords);
  72. QByteArray sa = searchTerm.toUtf8();
  73. int scMaxIndex = sa.length()-1;
  74. const char *sc = sa.constData();
  75. QByteArray sal = searchTerm.toLower().toUtf8();
  76. const char *scl = sal.constData();
  77. QByteArray sau = searchTerm.toUpper().toUtf8();
  78. const char *scu = sau.constData();
  79. int chunkSize = qMax(100000, sa.length());
  80. QFile file;
  81. QBuffer buffer;
  82. foreach (QString s, files) {
  83. if (future.isPaused())
  84. future.waitForResume();
  85. if (future.isCanceled()) {
  86. future.setProgressValueAndText(numFilesSearched, msgCanceled(searchTerm, numMatches, numFilesSearched));
  87. break;
  88. }
  89. QIODevice *device;
  90. if (fileToContentsMap.contains(s)) {
  91. buffer.setData(fileToContentsMap.value(s).toLocal8Bit());
  92. device = &buffer;
  93. } else {
  94. file.setFileName(s);
  95. device = &file;
  96. }
  97. if (!device->open(QIODevice::ReadOnly))
  98. continue;
  99. int lineNr = 1;
  100. const char *startOfLastLine = NULL;
  101. bool firstChunk = true;
  102. while (!device->atEnd()) {
  103. if (!firstChunk)
  104. device->seek(device->pos()-sa.length()+1);
  105. const QByteArray chunk = device->read(chunkSize);
  106. const char *chunkPtr = chunk.constData();
  107. startOfLastLine = chunkPtr;
  108. for (const char *regionPtr = chunkPtr; regionPtr < chunkPtr + chunk.length()-scMaxIndex; ++regionPtr) {
  109. const char *regionEnd = regionPtr + scMaxIndex;
  110. if (*regionPtr == '\n') {
  111. startOfLastLine = regionPtr + 1;
  112. ++lineNr;
  113. }
  114. else if (
  115. // case sensitive
  116. (!caseInsensitive && *regionPtr == sc[0] && *regionEnd == sc[scMaxIndex])
  117. ||
  118. // case insensitive
  119. (caseInsensitive && (*regionPtr == scl[0] || *regionPtr == scu[0])
  120. && (*regionEnd == scl[scMaxIndex] || *regionEnd == scu[scMaxIndex]))
  121. ) {
  122. const char *afterRegion = regionEnd + 1;
  123. const char *beforeRegion = regionPtr - 1;
  124. bool equal = true;
  125. if (wholeWord &&
  126. ( isalnum(*beforeRegion)
  127. || (*beforeRegion == '_')
  128. || isalnum(*afterRegion)
  129. || (*afterRegion == '_'))) {
  130. equal = false;
  131. }
  132. int regionIndex = 1;
  133. for (const char *regionCursor = regionPtr + 1; regionCursor < regionEnd; ++regionCursor, ++regionIndex) {
  134. if ( // case sensitive
  135. (!caseInsensitive && equal && *regionCursor != sc[regionIndex])
  136. ||
  137. // case insensitive
  138. (caseInsensitive && equal && *regionCursor != sc[regionIndex] && *regionCursor != scl[regionIndex] && *regionCursor != scu[regionIndex])
  139. ) {
  140. equal = false;
  141. }
  142. }
  143. if (equal) {
  144. int textLength = chunk.length() - (startOfLastLine - chunkPtr);
  145. if (textLength > 0) {
  146. QByteArray res;
  147. res.reserve(256);
  148. int i = 0;
  149. int n = 0;
  150. while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256)
  151. res.append(startOfLastLine[i++]);
  152. future.reportResult(FileSearchResult(s, lineNr, QString(res),
  153. regionPtr - startOfLastLine, sa.length()));
  154. ++numMatches;
  155. }
  156. }
  157. }
  158. }
  159. firstChunk = false;
  160. }
  161. ++numFilesSearched;
  162. future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched, files.size()));
  163. device->close();
  164. }
  165. if (!future.isCanceled())
  166. future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched));
  167. }
  168. void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future,
  169. QString searchTerm,
  170. QStringList files,
  171. QTextDocument::FindFlags flags,
  172. QMap<QString, QString> fileToContentsMap)
  173. {
  174. future.setProgressRange(0, files.size());
  175. int numFilesSearched = 0;
  176. int numMatches = 0;
  177. if (flags & QTextDocument::FindWholeWords)
  178. searchTerm = QString::fromLatin1("\\b%1\\b").arg(searchTerm);
  179. const Qt::CaseSensitivity caseSensitivity = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive;
  180. const QRegExp expression(searchTerm, caseSensitivity);
  181. QFile file;
  182. QString str;
  183. QTextStream stream;
  184. foreach (const QString &s, files) {
  185. if (future.isPaused())
  186. future.waitForResume();
  187. if (future.isCanceled()) {
  188. future.setProgressValueAndText(numFilesSearched, msgCanceled(searchTerm, numMatches, numFilesSearched));
  189. break;
  190. }
  191. bool needsToCloseFile = false;
  192. if (fileToContentsMap.contains(s)) {
  193. str = fileToContentsMap.value(s);
  194. stream.setString(&str);
  195. } else {
  196. file.setFileName(s);
  197. if (!file.open(QIODevice::ReadOnly))
  198. continue;
  199. needsToCloseFile = true;
  200. stream.setDevice(&file);
  201. }
  202. int lineNr = 1;
  203. QString line;
  204. while (!stream.atEnd()) {
  205. line = stream.readLine();
  206. int pos = 0;
  207. while ((pos = expression.indexIn(line, pos)) != -1) {
  208. future.reportResult(FileSearchResult(s, lineNr, line,
  209. pos, expression.matchedLength()));
  210. pos += expression.matchedLength();
  211. }
  212. ++lineNr;
  213. }
  214. ++numFilesSearched;
  215. future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched, files.size()));
  216. if (needsToCloseFile)
  217. file.close();
  218. }
  219. if (!future.isCanceled())
  220. future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched));
  221. }
  222. } // namespace
  223. QFuture<FileSearchResult> Utils::findInFiles(const QString &searchTerm, const QStringList &files,
  224. QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap)
  225. {
  226. return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> >
  227. (runFileSearch, searchTerm, files, flags, fileToContentsMap);
  228. }
  229. QFuture<FileSearchResult> Utils::findInFilesRegExp(const QString &searchTerm, const QStringList &files,
  230. QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap)
  231. {
  232. return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> >
  233. (runFileSearchRegExp, searchTerm, files, flags, fileToContentsMap);
  234. }