OSDN Git Service

PATCH: [ 804493 ] Read filter files from users profile directory
[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 // I think that CRegExp doesn't copy correctly (I get heap corruption in CRegList::program)
23 // so I'm using pointers to avoid its copy constructor
24 // Perry, 2003-05-18
25
26 typedef CTypedPtrList<CPtrList, CRegExp*>RegList;
27 static void DeleteRegList(RegList & reglist)
28 {
29         while (!reglist.IsEmpty())
30         {
31                 CRegExp * regexp = reglist.RemoveHead();
32                 delete regexp;
33         }
34 }
35 // One actual filter
36 // For example, this might be a GNU C filter, excluding *.o files and CVS directories
37 // That is to say, a filter is a set of file masks and directory masks
38 struct FileFilter
39 {
40         bool default_include;
41         CString name;
42         CString fullpath;
43         RegList filefilters; 
44         RegList dirfilters; 
45         FileFilter() : default_include(true) { }
46         ~FileFilter();
47 };
48 FileFilter::~FileFilter()
49 {
50         DeleteRegList(filefilters);
51         DeleteRegList(dirfilters);
52 }
53
54 FileFilterMgr::~FileFilterMgr()
55 {
56         DeleteAllFilters();
57 }
58
59 // Load 
60 void FileFilterMgr::LoadFromDirectory(LPCTSTR szPattern, LPCTSTR szExt)
61 {
62         // DeleteAllFilters();
63         CFileFind finder;
64         BOOL bWorking = finder.FindFile(szPattern);
65         int extlen = szExt ? _tcslen(szExt) : 0;
66         while (bWorking)
67         {
68                 bWorking = finder.FindNextFile();
69                 if (finder.IsDots() || finder.IsDirectory())
70                         continue;
71                 CString sFilename = finder.GetFileName();
72                 if (szExt)
73                 {
74                         // caller specified a specific extension
75                         // (This is really a workaround for brokenness in windows, which
76                         //  doesn't screen correctly on extension in pattern)
77                         if (sFilename.Right(extlen).CompareNoCase(szExt))
78                                 return;
79                 }
80                 FileFilter * pfilter = LoadFilterFile(finder.GetFilePath(), sFilename);
81                 m_filters.Add(pfilter);
82         }
83 }
84
85 void FileFilterMgr::DeleteAllFilters()
86 {
87         for (int i=0; i<m_filters.GetSize(); ++i)
88         {
89                 delete m_filters[i];
90                 m_filters[i] = 0;
91         }
92         m_filters.RemoveAll();
93 }
94
95 // Add a single pattern (if nonempty & valid) to a pattern list
96 static void AddFilterPattern(RegList & reglist, CString & str)
97 {
98         str.TrimLeft();
99         str.MakeUpper();
100         LPCTSTR commentLeader = _T(" ##");
101         // anything from commentLeader to end of line is a comment
102         int comment = str.Find(commentLeader);
103         if (comment >= 0)
104         {
105                 str = str.Left(comment);
106         }
107         if (str.IsEmpty()) return;
108         CRegExp * regexp = new CRegExp;
109         if (regexp->RegComp(str))
110                 reglist.AddTail(regexp);
111         else
112                 delete regexp;
113 }
114
115 // Parse a filter file, and add it to array if valid
116 FileFilter * FileFilterMgr::LoadFilterFile(LPCTSTR szFilepath, LPCTSTR szFilename)
117 {
118         CStdioFile file;
119         if (!file.Open(szFilepath, CFile::modeRead))
120                 return NULL;
121         FileFilter *pfilter = new FileFilter;
122         pfilter->fullpath = szFilepath;
123         pfilter->name = szFilename; // default if no name
124         CString sLine;
125         while (file.ReadString(sLine))
126         {
127                 if (0 == _tcsncmp(sLine, _T("name:"), 5))
128                 {
129                         // specifies display name
130                         CString str = sLine.Mid(5);
131                         str.TrimLeft();
132                         if (!str.IsEmpty())
133                                 pfilter->name = str;
134                 }
135                 else if (0 == _tcsncmp(sLine, _T("def:"), 4))
136                 {
137                         // specifies default
138                         CString str = sLine.Mid(4);
139                         str.TrimLeft();
140                         if (str == _T("0") || str == _T("no") || str == _T("exclude"))
141                                 pfilter->default_include = false;
142                         else if (str == _T("1") || str == _T("yes") || str == _T("include"))
143                                 pfilter->default_include = true;
144                 }
145                 else if (0 == _tcsncmp(sLine, _T("f:"), 2))
146                 {
147                         // file filter
148                         CString str = sLine.Mid(2);
149                         AddFilterPattern(pfilter->filefilters, str);
150                 }
151                 else if (0 == _tcsncmp(sLine, _T("d:"), 2))
152                 {
153                         // directory filter
154                         CString str = sLine.Mid(2);
155                         AddFilterPattern(pfilter->dirfilters, str);
156                 }
157         }
158         return pfilter;
159 }
160
161 // Give client back a pointer to the actual filter
162 // We just do a linear search, because this is seldom called
163 FileFilter * FileFilterMgr::GetFilter(LPCTSTR szFilterName)
164 {
165         for (int i=0; i<m_filters.GetSize(); ++i)
166         {
167                 if (m_filters[i]->name == szFilterName)
168                         return m_filters[i];
169         }
170         return 0;
171 }
172
173 // return TRUE if string passes
174 BOOL TestAgainstRegList(const RegList & reglist, LPCTSTR szTest)
175 {
176         CString str = szTest;
177         str.MakeUpper();
178         for (POSITION pos = reglist.GetHeadPosition(); pos; )
179         {
180                 CRegExp * regexp = reglist.GetNext(pos);
181                 if (regexp->RegFind(str) != -1)
182                         return TRUE;
183         }
184         return FALSE;
185 }
186
187 // return TRUE if file passes the filter
188 BOOL FileFilterMgr::TestFileNameAgainstFilter(FileFilter * pFilter, LPCTSTR szFileName)
189 {
190         if (!pFilter) return TRUE;
191         if (TestAgainstRegList(pFilter->filefilters, szFileName))
192                 return !pFilter->default_include;
193         return pFilter->default_include;
194 }
195
196 // return TRUE if directory passes the filter
197 BOOL FileFilterMgr::TestDirNameAgainstFilter(FileFilter * pFilter, LPCTSTR szDirName)
198 {
199         if (!pFilter) return TRUE;
200         if (TestAgainstRegList(pFilter->dirfilters, szDirName))
201                 return !pFilter->default_include;
202         return pFilter->default_include;
203 }
204
205 CString FileFilterMgr::GetFilterName(int i)
206 {
207         return m_filters[i]->name; 
208 }
209
210 CString FileFilterMgr::GetFullpath(FileFilter * pfilter) const
211 {
212         return pfilter->fullpath;
213 }
214
215 // Reload filter from disk (by creating a new one to substitute for old one)
216 void FileFilterMgr::ReloadFilterFromDisk(FileFilter * pfilter)
217 {
218         FileFilter * newfilter = LoadFilterFile(pfilter->fullpath, pfilter->name);
219         for (int i=0; i<m_filters.GetSize(); ++i)
220         {
221                 if (pfilter == m_filters[i])
222                 {
223                         m_filters.RemoveAt(i);
224                         delete pfilter;
225                         break;
226                 }
227         }
228         m_filters.Add(newfilter);
229 }