SearchThread.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:10k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // SearchThread.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "grep.h"
  5. #include "SearchThread.h"
  6. #include "SearchOptions.h"
  7. #include "MainFrm.h"
  8. #include "GrepView.h"
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14. /////////////////////////////////////////////////////////////////////////////
  15. // CSearchThread
  16. IMPLEMENT_DYNCREATE(CSearchThread, CWinThread)
  17. long GetLineNumber(TCHAR* lpszFileBuffer, int nIndex)
  18. {
  19. long nLine = 1;
  20. while (nIndex--)
  21. {
  22. if (*lpszFileBuffer == _T('n')) nLine++;
  23. lpszFileBuffer++;
  24. }
  25. return nLine;
  26. }
  27. void CSearchThread::AddRecord(CXTPReportControl& wndControl, TCHAR* lpszFileBuffer, TCHAR* lpszEndBuffer, long nIndex, long nLength,
  28. CString strMatch, CString strReplace, CString strPath, CFileFind& finder)
  29. {
  30. USES_CONVERSION;
  31. TCHAR* lpszMatch = lpszFileBuffer + nIndex;
  32. TCHAR* lpszMatchBeginLine = lpszMatch;
  33. TCHAR* lpszMatchEndLine = lpszMatchBeginLine + nLength;
  34. int nMaxPreview = 80;
  35. while (nMaxPreview-- && lpszMatchBeginLine != lpszFileBuffer && *(lpszMatchBeginLine - 1) != 'n')
  36. lpszMatchBeginLine--;
  37. if (*lpszMatchEndLine != 'n')
  38. {
  39. nMaxPreview = 80;
  40. while (nMaxPreview-- && lpszMatchEndLine != lpszEndBuffer && *(lpszMatchEndLine + 1) != 'n' )
  41. lpszMatchEndLine++;
  42. }
  43. TCHAR tchEndLine = *lpszMatchEndLine;
  44. *lpszMatchEndLine = '';
  45. CString strBeginLine;
  46. long nBeginLineLength = long(lpszMatch - lpszMatchBeginLine);
  47. STRNCPY_S(strBeginLine.GetBufferSetLength(nBeginLineLength), nBeginLineLength + 1, lpszMatchBeginLine, nBeginLineLength);
  48. CString strEndLine;
  49. long nEndLineLength = long(lpszMatchEndLine - lpszMatch - nLength);
  50. STRNCPY_S(strEndLine.GetBufferSetLength(nEndLineLength), nEndLineLength + 1, lpszMatch + nLength, nEndLineLength);
  51. wndControl.AddRecord(new CGrepRecord
  52. (finder.GetFilePath(), strPath, finder.GetFileName(), strMatch,
  53. GetLineNumber(lpszFileBuffer, nIndex),
  54. strBeginLine + strMatch + strEndLine,
  55. strBeginLine + strReplace + strEndLine, nIndex, nLength, strReplace));
  56. *lpszMatchEndLine = tchEndLine;
  57. m_searchResult.nMatchingLines++;
  58. }
  59. void CSearchThread::SetMessageText()
  60. {
  61. CString strMessage;
  62. strMessage.Format(_T("Matching lines: %i        Matching files: %i        Total files searched: %i"), 
  63. m_searchResult.nMatchingLines, m_searchResult.nMatchingFiles, m_searchResult.nTotalFiles);
  64. m_pMainFrame->SetMessageText(strMessage);
  65. m_pMainFrame->DelayPopulate();
  66. }
  67. #ifdef _UNICODE
  68. #define CT2BSTR(x) (BSTR)(LPCWSTR)x
  69. #else
  70. #define CT2BSTR(x) (BSTR)A2CW(x)
  71. #endif
  72. int FindNext(const CString& str, const CString& strFind, int nIndex, CSearchOptions* pOptions)
  73. {
  74. nIndex = FIND_S(str, strFind, nIndex);
  75. if (!pOptions->m_bMatchWholeWords)
  76. return nIndex;
  77. static LPCTSTR szSeps = _T("() t<>{}:;,.=%"'!@#$^&*-\|[]/?rn");
  78. while (nIndex != -1)
  79. {
  80. BOOL bSepAfter = FALSE;
  81. BOOL bSepBefore = FALSE;
  82. if (nIndex + strFind.GetLength() >= str.GetLength())
  83. bSepAfter = TRUE;
  84. else
  85. bSepAfter = (_tcschr(szSeps, str[nIndex + strFind.GetLength()]) != 0);
  86. if (nIndex == 0)
  87. bSepBefore = TRUE;
  88. else
  89. bSepBefore = (_tcschr(szSeps, str[nIndex - 1]) != 0);
  90. if (bSepAfter && bSepBefore)
  91. return nIndex;
  92.  
  93. nIndex = FIND_S(str, strFind, nIndex + 1);
  94. }
  95. return nIndex;
  96. }
  97. BOOL CSearchThread::ProcessFile(CString strPath, CFileFind& finder)
  98. {
  99. USES_CONVERSION;
  100. if (!m_pReportControl)
  101. return FALSE;
  102. CSearchOptions* pOptions = GetSearchOptions();
  103. ASSERT(pOptions);
  104. CFile file;
  105. if (!file.Open(finder.GetFilePath(), CFile::modeRead))
  106. return TRUE;
  107. DWORD dwCount = (DWORD)file.GetLength();
  108. char* pchData = new char[dwCount + 1];
  109. file.Read(pchData, dwCount);
  110. pchData[dwCount] = 0;
  111. #ifdef _UNICODE
  112. TCHAR* lpszFileBuffer = new TCHAR[dwCount + 1];
  113. _mbstowcsz(lpszFileBuffer, pchData, dwCount+1);
  114. #else
  115. char* lpszFileBuffer = pchData;
  116. #endif
  117. file.Close();
  118. TCHAR* lpszEndBuffer = lpszFileBuffer + dwCount;
  119. BOOL bContinue = TRUE;
  120. if (!pOptions->pRegExp)
  121. {
  122. CString str(lpszFileBuffer);
  123. CString strFind = pOptions->m_strFind;
  124. if (!pOptions->m_bMatchCase)
  125. {
  126. str.MakeLower();
  127. strFind.MakeLower();
  128. }
  129. int nLength = strFind.GetLength();
  130. int nIndex = FindNext(str, strFind, 0, pOptions);
  131. if (nIndex != -1)
  132. {
  133. m_searchResult.nMatchingFiles++;
  134. }
  135. while (nIndex != -1)
  136. {
  137. CString strMatch;
  138. STRNCPY_S(strMatch.GetBufferSetLength(nLength), nLength + 1, lpszFileBuffer + nIndex, nLength);
  139. if (m_bCancel)
  140. {
  141. bContinue = FALSE;
  142. break;
  143. }
  144. CString strReplace = pOptions->m_strReplace;
  145. AddRecord(*m_pReportControl, lpszFileBuffer, lpszEndBuffer, nIndex, nLength,
  146. strMatch, strReplace, strPath, finder);
  147. nIndex = FindNext(str, strFind, nIndex + 1, pOptions);
  148. }
  149. }
  150. else
  151. {
  152. try
  153. {
  154. #ifndef _UNICODE
  155. BSTR bstrBuffer = new WCHAR[dwCount + 1];
  156. _mbstowcsz(bstrBuffer, lpszFileBuffer, dwCount+1);
  157. #else
  158. BSTR bstrBuffer = (BSTR)lpszFileBuffer;
  159. #endif
  160. IMatchCollectionPtr MatchesPtr = pOptions->pRegExp->Execute(bstrBuffer);
  161. int nCount = MatchesPtr.GetInterfacePtr()? MatchesPtr->Count: 0;
  162. if (nCount > 0)
  163. {
  164. m_searchResult.nMatchingFiles++;
  165. }
  166. for (int i = 0; i < nCount; i++)
  167. {
  168. IMatchPtr MatchPtr = MatchesPtr->Item[i];
  169. int nIndex = MatchPtr->FirstIndex;
  170. int nLength =MatchPtr->Length;
  171. CString strMatch;
  172. STRNCPY_S(strMatch.GetBufferSetLength(nLength), nLength + 1, lpszFileBuffer + nIndex, nLength);
  173. _bstr_t bstrResult =pOptions->pRegExp->Replace(CT2BSTR(strMatch), CT2BSTR(pOptions->m_strReplace));
  174. CString strReplace = (LPCWSTR)bstrResult;
  175. if (m_bCancel)
  176. {
  177. bContinue = FALSE;
  178. break;
  179. }
  180. AddRecord(*m_pReportControl, lpszFileBuffer, lpszEndBuffer, nIndex, nLength,
  181. strMatch, strReplace, strPath, finder);
  182. }
  183. #ifndef _UNICODE
  184. delete[] bstrBuffer;
  185. #endif
  186. }
  187. catch (_com_error& e)
  188. {
  189. CString strDescription(BSTR(e.Description()));
  190. if (strDescription.IsEmpty())
  191. strDescription = _T("Error in regular expression.");
  192. strDescription += " Continue?";
  193. bContinue = AfxMessageBox(strDescription, MB_YESNO) == IDNO? FALSE: TRUE;
  194. }
  195. }
  196. delete[] lpszFileBuffer;
  197. #ifdef _UNICODE
  198. delete[] pchData;
  199. #endif
  200. if (bContinue)
  201. {
  202. SetMessageText();
  203. }
  204. return bContinue;
  205. }
  206. BOOL MatchFileType(CString strFileName, CString strMask)
  207. {
  208. if (strMask == _T("*.*"))
  209. return TRUE;
  210. strMask.MakeLower();
  211. strFileName.MakeLower();
  212. strFileName += _T(";");
  213. strMask += _T(";");
  214. CString str = strMask;
  215. while (str != _T(";") && str != _T(""))
  216. {
  217. int nIndex = str.Find(_T(';'));
  218. if (nIndex != -1)
  219. {
  220. strMask = str.Mid(nIndex + 1);
  221. str = str.Left(nIndex + 1);
  222. }
  223. else
  224. {
  225. strMask.Empty();
  226. }
  227. REPLACE_S(str, _T("*;"), _T(""));
  228. REPLACE_S(str, _T(";*"), _T(""));
  229. REPLACE_S(str, _T("*"), _T(""));
  230. if (strFileName.Find(str) >= 0)
  231. return TRUE;
  232. str = strMask;
  233. }
  234. return FALSE;
  235. }
  236. BOOL CSearchThread::ProcessPath(CString strPath)
  237. {
  238. CFileFind finder;
  239. CString strWildcard = strPath + _T("\*.*") ;
  240. // start working for files
  241. BOOL bWorking = finder.FindFile(strWildcard);
  242. while (bWorking)
  243. {
  244. bWorking = finder.FindNextFile();
  245. // skip . and .. files; otherwise, we'd
  246. // recur infinitely!
  247. if (finder.IsDots())
  248. continue;
  249. // if it's a directory, recursively search it
  250. if (finder.IsDirectory())
  251. {
  252. if (GetSearchOptions()->m_bIncludeSubFolders)
  253. {
  254. if (GetSearchOptions()->m_bFindInHiddenFiles || !finder.IsHidden())
  255. {
  256. if (!ProcessPath(finder.GetFilePath()))
  257. return FALSE;
  258. }
  259. }
  260. continue;
  261. }
  262. if (MatchFileType(finder.GetFileName(), GetSearchOptions()->m_strFileTypes))
  263. {
  264. if (GetSearchOptions()->m_bFindInHiddenFiles || !finder.IsHidden())
  265. {
  266. m_searchResult.nTotalFiles++;
  267. if (!ProcessFile(strPath, finder))
  268. return FALSE;
  269. }
  270. }
  271. if (m_bCancel)
  272. return FALSE;
  273. }
  274. finder.Close();
  275. return TRUE;
  276. }
  277. CSearchThread::CSearchThread()
  278. {
  279. m_pMainFrame = NULL;
  280. m_pReportControl = NULL;
  281. m_bAutoDelete = TRUE;
  282. m_bCancel = FALSE;
  283. ZeroMemory(&m_searchResult, sizeof(SEARCH_RESULT));
  284. }
  285. CSearchThread::~CSearchThread()
  286. {
  287. }
  288. BOOL CSearchThread::InitInstance()
  289. {
  290. USES_CONVERSION;
  291. AfxOleInit();
  292. IRegExpPtr regExp;
  293. CSearchOptions* pOptions = GetSearchOptions();
  294. ASSERT(pOptions);
  295. if (pOptions->m_bRegularExpressions)
  296. {
  297. HRESULT hr = regExp.CreateInstance(__uuidof(RegExp));
  298. if (FAILED(hr))
  299. {
  300. AfxMessageBox(_T("RegExp not found"));
  301. }
  302. else
  303. {
  304. pOptions->pRegExp = regExp;
  305. regExp->Global = VARIANT_TRUE;
  306. regExp->IgnoreCase = pOptions->m_bMatchCase? VARIANT_FALSE: VARIANT_TRUE;
  307. regExp->Pattern = _bstr_t(CT2BSTR(pOptions->m_strFind));
  308. }
  309. }
  310. ProcessPath(pOptions->m_strPath);
  311. pOptions->pRegExp = 0;
  312. // TODO:  perform and per-thread initialization here
  313. return FALSE;
  314. }
  315. int CSearchThread::ExitInstance()
  316. {
  317. m_pMainFrame->PostMessage(WM_SEARCHFINISHED);
  318. // TODO:  perform any per-thread cleanup here
  319. return CWinThread::ExitInstance();
  320. }
  321. BEGIN_MESSAGE_MAP(CSearchThread, CWinThread)
  322. //{{AFX_MSG_MAP(CSearchThread)
  323. // NOTE - the ClassWizard will add and remove mapping macros here.
  324. //}}AFX_MSG_MAP
  325. END_MESSAGE_MAP()
  326. /////////////////////////////////////////////////////////////////////////////
  327. // CSearchThread message handlers