OSDN Git Service

[ 807263 ] Preprocessing patch
[winmerge-jp/winmerge-jp.git] / Src / FileFilterMgr.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // FileFilterMgr.cpp : implementation file
3 // see FileFilterMgr.h for description
4 /////////////////////////////////////////////////////////////////////////////
5 //    License (GPLv2+):
6 //    This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
7 //    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
8 //    You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
9 /////////////////////////////////////////////////////////////////////////////
10 //
11
12 #include "stdafx.h"
13 #include "FileFilterMgr.h"
14 #include "RegExp.h"
15
16 #ifdef _DEBUG
17 #define new DEBUG_NEW
18 #undef THIS_FILE
19 static char THIS_FILE[] = __FILE__;
20 #endif
21
22 void DeleteRegList(RegList & reglist)
23 {
24         while (!reglist.IsEmpty())
25         {
26                 CRegExp * regexp = reglist.RemoveHead();
27                 delete regexp;
28         }
29 }
30 // One actual filter
31 // For example, this might be a GNU C filter, excluding *.o files and CVS directories
32 // That is to say, a filter is a set of file masks and directory masks
33 struct FileFilter
34 {
35         bool default_include;
36         CString name;
37         CString fullpath;
38         RegList filefilters; 
39         RegList dirfilters; 
40         FileFilter() : default_include(true) { }
41         ~FileFilter();
42 };
43 FileFilter::~FileFilter()
44 {
45         DeleteRegList(filefilters);
46         DeleteRegList(dirfilters);
47 }
48
49 FileFilterMgr::~FileFilterMgr()
50 {
51         DeleteAllFilters();
52 }
53
54 // Load 
55 void FileFilterMgr::LoadFromDirectory(LPCTSTR szPattern, LPCTSTR szExt)
56 {
57         // DeleteAllFilters();
58         CFileFind finder;
59         BOOL bWorking = finder.FindFile(szPattern);
60         int extlen = szExt ? _tcslen(szExt) : 0;
61         while (bWorking)
62         {
63                 bWorking = finder.FindNextFile();
64                 if (finder.IsDots() || finder.IsDirectory())
65                         continue;
66                 CString sFilename = finder.GetFileName();
67                 if (szExt)
68                 {
69                         // caller specified a specific extension
70                         // (This is really a workaround for brokenness in windows, which
71                         //  doesn't screen correctly on extension in pattern)
72                         if (sFilename.Right(extlen).CompareNoCase(szExt))
73                                 return;
74                 }
75                 FileFilter * pfilter = LoadFilterFile(finder.GetFilePath(), sFilename);
76                 m_filters.Add(pfilter);
77         }
78 }
79
80 void FileFilterMgr::DeleteAllFilters()
81 {
82         for (int i=0; i<m_filters.GetSize(); ++i)
83         {
84                 delete m_filters[i];
85                 m_filters[i] = 0;
86         }
87         m_filters.RemoveAll();
88 }
89
90 // Add a single pattern (if nonempty & valid) to a pattern list
91 // str is a temporary variable (ie, it may be altered)
92 static void AddFilterPattern(RegList & reglist, CString & str)
93 {
94         str.TrimLeft();
95         str.MakeUpper();
96         LPCTSTR commentLeader = _T(" ##");
97         // anything from commentLeader to end of line is a comment
98         int comment = str.Find(commentLeader);
99         if (comment >= 0)
100         {
101                 str = str.Left(comment);
102         }
103         if (str.IsEmpty()) return;
104         CRegExp * regexp = new CRegExp;
105         if (regexp->RegComp(str))
106                 reglist.AddTail(regexp);
107         else
108                 delete regexp;
109 }
110
111 // Parse a filter file, and add it to array if valid
112 FileFilter * FileFilterMgr::LoadFilterFile(LPCTSTR szFilepath, LPCTSTR szFilename)
113 {
114         CStdioFile file;
115         if (!file.Open(szFilepath, CFile::modeRead))
116                 return NULL;
117         FileFilter *pfilter = new FileFilter;
118         pfilter->fullpath = szFilepath;
119         pfilter->name = szFilename; // default if no name
120         CString sLine;
121         while (file.ReadString(sLine))
122         {
123                 if (0 == _tcsncmp(sLine, _T("name:"), 5))
124                 {
125                         // specifies display name
126                         CString str = sLine.Mid(5);
127                         str.TrimLeft();
128                         if (!str.IsEmpty())
129                                 pfilter->name = str;
130                 }
131                 else if (0 == _tcsncmp(sLine, _T("def:"), 4))
132                 {
133                         // specifies default
134                         CString str = sLine.Mid(4);
135                         str.TrimLeft();
136                         if (str == _T("0") || str == _T("no") || str == _T("exclude"))
137                                 pfilter->default_include = false;
138                         else if (str == _T("1") || str == _T("yes") || str == _T("include"))
139                                 pfilter->default_include = true;
140                 }
141                 else if (0 == _tcsncmp(sLine, _T("f:"), 2))
142                 {
143                         // file filter
144                         CString str = sLine.Mid(2);
145                         AddFilterPattern(pfilter->filefilters, str);
146                 }
147                 else if (0 == _tcsncmp(sLine, _T("d:"), 2))
148                 {
149                         // directory filter
150                         CString str = sLine.Mid(2);
151                         AddFilterPattern(pfilter->dirfilters, str);
152                 }
153         }
154         return pfilter;
155 }
156
157 // Give client back a pointer to the actual filter
158 // We just do a linear search, because this is seldom called
159 FileFilter * FileFilterMgr::GetFilterByPath(LPCTSTR szFilterPath)
160 {
161         for (int i=0; i<m_filters.GetSize(); ++i)
162         {
163                 if (m_filters[i]->fullpath == szFilterPath)
164                         return m_filters[i];
165         }
166         return 0;
167 }
168
169 // return TRUE if string passes
170 BOOL TestAgainstRegList(const RegList & reglist, LPCTSTR szTest)
171 {
172         CString str = szTest;
173         str.MakeUpper();
174         for (POSITION pos = reglist.GetHeadPosition(); pos; )
175         {
176                 CRegExp * regexp = reglist.GetNext(pos);
177                 if (regexp->RegFind(str) != -1)
178                         return TRUE;
179         }
180         return FALSE;
181 }
182
183 // return TRUE if file passes the filter
184 BOOL FileFilterMgr::TestFileNameAgainstFilter(FileFilter * pFilter, LPCTSTR szFileName)
185 {
186         if (!pFilter) return TRUE;
187         if (TestAgainstRegList(pFilter->filefilters, szFileName))
188                 return !pFilter->default_include;
189         return pFilter->default_include;
190 }
191
192 // return TRUE if directory passes the filter
193 BOOL FileFilterMgr::TestDirNameAgainstFilter(FileFilter * pFilter, LPCTSTR szDirName)
194 {
195         if (!pFilter) return TRUE;
196         if (TestAgainstRegList(pFilter->dirfilters, szDirName))
197                 return !pFilter->default_include;
198         return pFilter->default_include;
199 }
200
201 CString FileFilterMgr::GetFilterName(int i) const
202 {
203         return m_filters[i]->name; 
204 }
205
206 CString FileFilterMgr::GetFilterPath(int i) const
207 {
208         return m_filters[i]->fullpath;
209 }
210
211 CString FileFilterMgr::GetFullpath(FileFilter * pfilter) const
212 {
213         return pfilter->fullpath;
214 }
215
216 // Reload filter from disk (by creating a new one to substitute for old one)
217 void FileFilterMgr::ReloadFilterFromDisk(FileFilter * pfilter)
218 {
219         FileFilter * newfilter = LoadFilterFile(pfilter->fullpath, pfilter->name);
220         for (int i=0; i<m_filters.GetSize(); ++i)
221         {
222                 if (pfilter == m_filters[i])
223                 {
224                         m_filters.RemoveAt(i);
225                         delete pfilter;
226                         break;
227                 }
228         }
229         m_filters.Add(newfilter);
230 }