/** This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3* http://www.gnu.org/licenses/gpl-3.0.html** $Revision$* $Id$* $HeadURL$*/#include <sdk.h>#ifndef CB_PRECOMP#include <wx/app.h> // wxPostEvent#include <wx/dir.h> // wxDirTraverser#include <wx/event.h>#include <wx/filename.h>#endif#include "systemheadersthread.h"#define CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT 0#if defined(CC_GLOBAL_DEBUG_OUTPUT)#if CC_GLOBAL_DEBUG_OUTPUT == 1#undef CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT#define CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT 1#elif CC_GLOBAL_DEBUG_OUTPUT == 2#undef CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT#define CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT 2#endif#endif#if CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT == 1#define TRACE(format, args...) \CCLogger::Get()->DebugLog(F(format, ##args))#define TRACE2(format, args...)#elif CC_SYSTEMHEADERSTHREAD_DEBUG_OUTPUT == 2#define TRACE(format, args...) \do \{ \if (g_EnableDebugTrace) \CCLogger::Get()->DebugLog(F(format, ##args)); \} \while (false)#define TRACE2(format, args...) \CCLogger::Get()->DebugLog(F(format, ##args))#else#define TRACE(format, args...)#define TRACE2(format, args...)#endif// when finished collecting all files, the thread are going to die, send this eventlong idSystemHeadersThreadFinish = wxNewId();// when collect all files under one path, send this eventlong idSystemHeadersThreadUpdate = wxNewId();// could not open the path, send an error eventlong idSystemHeadersThreadError = wxNewId();// internal class declaration of HeaderDirTraverser (implementation below)class HeaderDirTraverser : public wxDirTraverser{public:HeaderDirTraverser(wxThread* thread, wxCriticalSection* critSect,SystemHeadersMap& headersMap, const wxString& searchDir);virtual ~HeaderDirTraverser();/** call back function when we meet a file */virtual wxDirTraverseResult OnFile(const wxString& filename);/** call back function when we meet a dir */virtual wxDirTraverseResult OnDir(const wxString& dirname);private:/** this function will be called every time we meet a file or a dir, and we count the file and* dir, we temporary leave the critical section to give other thread a change to access the file* maps.*/void AddLock(bool is_file);wxDirTraverseResult GetStatus(const wxString &path);private:/* the thread call Traverse() on this instance*/wxThread* m_Thread;/* critical section to protect accessing m_SystemHeadersMap */wxCriticalSection* m_SystemHeadersThreadCS;/* dir to files map, for example, you are two dirs c:/a and c:/b* so the map looks like: (usually the relative file path is stored* c:/a ---> {c:/a/a1.h, c:/a/a2.h} ---> {a1.h, a2.h}* c:/b ---> {c:/b/b1.h, c:/b/b2.h} ---> {b1.h, b2.h}*/const SystemHeadersMap& m_SystemHeadersMap;/// Set of already visited directories (stored as absolute paths).std::set<wxString> m_VisitedDirs;/* top level dir we are traversing header files */const wxString& m_SearchDir;/* string set for header files */StringSet& m_Headers;/** indicates whether the critical section is entered or not, used in AddLock() function*/bool m_Locked;/* numbers of dirs in the traversing */size_t m_Dirs;/* numbers of files in the traversing */size_t m_Files;};// class SystemHeadersThreadSystemHeadersThread::SystemHeadersThread(wxEvtHandler* parent,wxCriticalSection* critSect,SystemHeadersMap& headersMap,const wxArrayString& incDirs) :wxThread(wxTHREAD_JOINABLE),m_Parent(parent),m_SystemHeadersThreadCS(critSect),m_SystemHeadersMap(headersMap),m_IncludeDirs(incDirs){Create();SetPriority(60u);}SystemHeadersThread::~SystemHeadersThread(){TRACE(_T("SystemHeadersThread: Terminated."));}void* SystemHeadersThread::Entry(){wxArrayString dirs;{wxCriticalSectionLocker locker(*m_SystemHeadersThreadCS);for (size_t i=0; i<m_IncludeDirs.GetCount(); ++i){if (m_SystemHeadersMap.find(m_IncludeDirs[i]) == m_SystemHeadersMap.end()){dirs.Add(m_IncludeDirs[i]);m_SystemHeadersMap[m_IncludeDirs[i]] = StringSet();}}}// collect header files in each dir, this is done by HeaderDirTraverserfor (size_t i=0; i<dirs.GetCount(); ++i){if ( TestDestroy() )break;// check the dir is ready for traversingwxDir dir(dirs[i]);if ( !dir.IsOpened() ){CodeBlocksThreadEvent evt(wxEVT_COMMAND_MENU_SELECTED, idSystemHeadersThreadError);evt.SetClientData(this);evt.SetString(wxString::Format(_T("SystemHeadersThread: Unable to open: %s"), dirs[i].wx_str()));wxPostEvent(m_Parent, evt);continue;}TRACE(_T("SystemHeadersThread: Launching dir traverser for: %s"), dirs[i].wx_str());HeaderDirTraverser traverser(this, m_SystemHeadersThreadCS, m_SystemHeadersMap, dirs[i]);dir.Traverse(traverser, wxEmptyString, wxDIR_FILES | wxDIR_DIRS);TRACE(_T("SystemHeadersThread: Dir traverser finished for: %s"), dirs[i].wx_str());if ( TestDestroy() )break;CodeBlocksThreadEvent evt(wxEVT_COMMAND_MENU_SELECTED, idSystemHeadersThreadUpdate);evt.SetClientData(this);evt.SetString(wxString::Format(_T("SystemHeadersThread: %s , %lu"), dirs[i].wx_str(), static_cast<unsigned long>(m_SystemHeadersMap[dirs[i]].size())));wxPostEvent(m_Parent, evt);}if ( !TestDestroy() ){CodeBlocksThreadEvent evt(wxEVT_COMMAND_MENU_SELECTED, idSystemHeadersThreadFinish);evt.SetClientData(this);if (!dirs.IsEmpty())evt.SetString(wxString::Format(_T("SystemHeadersThread: Total number of paths: %lu"), static_cast<unsigned long>(dirs.GetCount())));wxPostEvent(m_Parent, evt);}TRACE(_T("SystemHeadersThread: Done."));return NULL;}// class HeaderDirTraverserHeaderDirTraverser::HeaderDirTraverser(wxThread* thread,wxCriticalSection* critSect,SystemHeadersMap& headersMap,const wxString& searchDir) :m_Thread(thread),m_SystemHeadersThreadCS(critSect),m_SystemHeadersMap(headersMap),m_SearchDir(searchDir),m_Headers(headersMap[searchDir]),m_Locked(false),m_Dirs(0),m_Files(0){}HeaderDirTraverser::~HeaderDirTraverser(){if (m_Locked)m_SystemHeadersThreadCS->Leave();}wxDirTraverseResult HeaderDirTraverser::OnFile(const wxString& filename){// HeaderDirTraverser is used in a worker thread, so call TestDestroy() as often as it can to// quickly terminate the threadif (m_Thread->TestDestroy())return wxDIR_STOP;AddLock(true); // true means we are adding a filewxFileName fn(filename);if (!fn.HasExt() || fn.GetExt().GetChar(0) == _T('h')){fn.MakeRelativeTo(m_SearchDir);wxString header(fn.GetFullPath());header.Replace(_T("\\"), _T("/"), true); // Unix stylem_Headers.insert(header);}return wxDIR_CONTINUE;}wxDirTraverseResult HeaderDirTraverser::OnDir(const wxString& dirname){// HeaderDirTraverser is used in a worker thread, so call TestDestroy() as often as it can to// quickly terminate the threadif (m_Thread->TestDestroy())return wxDIR_STOP;AddLock(false); // false means we are adding a dirwxString path = cbResolveSymLinkedDirPathRecursive(dirname);if (path.Last() != wxFILE_SEP_PATH)path.Append(wxFILE_SEP_PATH);return GetStatus(path);}void HeaderDirTraverser::AddLock(bool is_file){if (is_file)m_Files++;elsem_Dirs++;if ((m_Files+m_Dirs) % 100 == 1){TRACE(_T("HeaderDirTraverser: %lu directories and %lu files traversed. Unlocking temporarily."), static_cast<unsigned long>(m_Dirs), static_cast<unsigned long>(m_Files));if (m_Locked){m_SystemHeadersThreadCS->Leave();m_Locked = false;}m_SystemHeadersThreadCS->Enter();m_Locked = true;}}wxDirTraverseResult HeaderDirTraverser::GetStatus(const wxString &path){if (m_SystemHeadersMap.find(path) != m_SystemHeadersMap.end())return wxDIR_IGNORE;if (m_VisitedDirs.find(path) != m_VisitedDirs.end())return wxDIR_IGNORE;m_VisitedDirs.insert(path);return wxDIR_CONTINUE;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。