OSDN Git Service

Reduce compiler warnings
[winmerge-jp/winmerge-jp.git] / Src / FileFilterMgr.cpp
index 2bbfcfd..c8b0576 100644 (file)
@@ -1,42 +1,29 @@
-/////////////////////////////////////////////////////////////////////////////
-//    License (GPLv2+):
-//    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.
-//    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.
-//    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.
-/////////////////////////////////////////////////////////////////////////////
+// SPDX-License-Identifier: GPL-2.0-or-later
 /**
  *  @file FileFilterMgr.cpp
  *
  *  @brief Implementation of FileFilterMgr and supporting routines
  */ 
 
+#include "pch.h"
 #include "FileFilterMgr.h"
 #include <vector>
-#include <cstring>
 #include <Poco/String.h>
 #include <Poco/Glob.h>
-#include <Poco/DirectoryIterator.h>
 #include <Poco/RegularExpression.h>
+#include "DirTravel.h"
+#include "DirItem.h"
 #include "UnicodeString.h"
 #include "FileFilter.h"
 #include "UniFile.h"
 #include "paths.h"
 
 using std::vector;
-using Poco::DirectoryIterator;
 using Poco::Glob;
 using Poco::icompare;
 using Poco::RegularExpression;
 
-static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str);
+static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str, bool fileFilter);
 
 /**
  * @brief Destructor, frees all filters.
@@ -55,7 +42,7 @@ int FileFilterMgr::AddFilter(const String& szFilterFile)
 {
        int errorcode = FILTER_OK;
        FileFilter * pFilter = LoadFilterFile(szFilterFile, errorcode);
-       if (pFilter)
+       if (pFilter != nullptr)
                m_filters.push_back(FileFilterPtr(pFilter));
        return errorcode;
 }
@@ -68,33 +55,28 @@ int FileFilterMgr::AddFilter(const String& szFilterFile)
  */
 void FileFilterMgr::LoadFromDirectory(const String& dir, const String& szPattern, const String& szExt)
 {
-       const std::string u8ext = ucr::toUTF8(szExt);
-       const size_t extlen = u8ext.length();
-
        try
        {
-               DirectoryIterator it(ucr::toUTF8(dir));
-               DirectoryIterator end;
+               DirItemArray dirs, files;
+               LoadAndSortFiles(dir, &dirs, &files, false);
                Glob glb(ucr::toUTF8(szPattern));
        
-               for (; it != end; ++it)
+               for (DirItem& item: files)
                {
-                       if (it->isDirectory())
-                               continue;
-                       std::string filename = it.name();
-                       if (!glb.match(filename))
+                       String filename = item.filename;
+                       if (!glb.match(ucr::toUTF8(filename)))
                                continue;
-                       if (extlen)
+                       if (!szExt.empty())
                        {
                                // caller specified a specific extension
                                // (This is really a workaround for brokenness in windows, which
                                //  doesn't screen correctly on extension in pattern)
-                               std::string ext = filename.substr(filename.length() - extlen);
-                               if (icompare(u8ext, ext) != 0)
+                               const String ext = filename.substr(filename.length() - szExt.length());
+                               if (strutils::compare_nocase(szExt, ext) != 0)
                                        return;
                        }
 
-                       String filterpath = paths_ConcatPath(dir, ucr::toTString(filename));
+                       String filterpath = paths::ConcatPath(dir, filename);
                        AddFilter(filterpath);
                }
        }
@@ -114,7 +96,7 @@ void FileFilterMgr::RemoveFilter(const String& szFilterFile)
        vector<FileFilterPtr>::iterator iter = m_filters.begin();
        while (iter != m_filters.end())
        {
-               if (string_compare_nocase((*iter)->fullpath, szFilterFile) == 0)
+               if (strutils::compare_nocase((*iter)->fullpath, szFilterFile) == 0)
                {
                        m_filters.erase(iter);
                        break;
@@ -137,10 +119,10 @@ void FileFilterMgr::DeleteAllFilters()
  * @param [in] filterList List where pattern is added.
  * @param [in] str Temporary variable (ie, it may be altered)
  */
-static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str)
+static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String & str, bool fileFilter)
 {
        const String& commentLeader = _T("##"); // Starts comment
-       str = string_trim_ws_begin(str);
+       str = strutils::trim_ws_begin(str);
 
        // Ignore lines beginning with '##'
        size_t pos = str.find(commentLeader);
@@ -154,7 +136,7 @@ static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String &
        // Remove comment and whitespaces before it
        if (pos != std::string::npos)
                str = str.substr(0, pos);
-       str = string_trim_ws_end(str);
+       str = strutils::trim_ws_end(str);
        if (str.empty())
                return;
 
@@ -163,7 +145,7 @@ static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String &
        re_opts |= RegularExpression::RE_UTF8;
        try
        {
-               filterList->push_back(FileFilterElementPtr(new FileFilterElement(regexString, re_opts)));
+               filterList->push_back(FileFilterElementPtr(new FileFilterElement(regexString, re_opts, fileFilter)));
        }
        catch (...)
        {
@@ -175,8 +157,8 @@ static void AddFilterPattern(vector<FileFilterElementPtr> *filterList, String &
  * @brief Parse a filter file, and add it to array if valid.
  *
  * @param [in] szFilePath Path (w/ filename) to file to load.
- * @param [out] error Error-code if loading failed (returned NULL).
- * @return Pointer to new filter, or NULL if error (check error code too).
+ * @param [out] error Error-code if loading failed (returned `nullptr`).
+ * @return Pointer to new filter, or `nullptr` if error (check error code too).
  */
 FileFilter * FileFilterMgr::LoadFilterFile(const String& szFilepath, int & error)
 {
@@ -184,16 +166,19 @@ FileFilter * FileFilterMgr::LoadFilterFile(const String& szFilepath, int & error
        if (!file.OpenReadOnly(szFilepath))
        {
                error = FILTER_ERROR_FILEACCESS;
-               return NULL;
+               return nullptr;
        }
 
        file.ReadBom(); // in case it is a Unicode file, let UniMemFile handle BOM
+       if (!file.IsUnicode() && !ucr::CheckForInvalidUtf8(
+               reinterpret_cast<const char*>(file.GetBase()), static_cast<size_t>(file.GetFileSize())))
+               file.SetUnicoding(ucr::UTF8);
 
        String fileName;
-       paths_SplitFilename(szFilepath, NULL, &fileName, NULL);
+       paths::SplitFilename(szFilepath, nullptr, &fileName, nullptr);
        FileFilter *pfilter = new FileFilter;
        pfilter->fullpath = szFilepath;
-       pfilter->name = fileName; // Filename is the default name
+       pfilter->name = std::move(fileName); // Filename is the default name
 
        String sLine;
        bool lossy = false;
@@ -203,30 +188,30 @@ FileFilter * FileFilterMgr::LoadFilterFile(const String& szFilepath, int & error
                // Returns false when last line is read
                String tmpLine;
                bLinesLeft = file.ReadString(tmpLine, &lossy);
-               sLine = tmpLine;
-               sLine = string_trim_ws(sLine);
+               sLine = std::move(tmpLine);
+               sLine = strutils::trim_ws(sLine);
 
                if (0 == sLine.compare(0, 5, _T("name:"), 5))
                {
                        // specifies display name
                        String str = sLine.substr(5);
-                       str = string_trim_ws_begin(str);
+                       str = strutils::trim_ws_begin(str);
                        if (!str.empty())
-                               pfilter->name = str;
+                               pfilter->name = std::move(str);
                }
                else if (0 == sLine.compare(0, 5, _T("desc:"), 5))
                {
                        // specifies display name
                        String str = sLine.substr(5);
-                       str = string_trim_ws_begin(str);
+                       str = strutils::trim_ws_begin(str);
                        if (!str.empty())
-                               pfilter->description = str;
+                               pfilter->description = std::move(str);
                }
                else if (0 == sLine.compare(0, 4, _T("def:"), 4))
                {
                        // specifies default
                        String str = sLine.substr(4);
-                       str = string_trim_ws_begin(str);
+                       str = strutils::trim_ws_begin(str);
                        if (str == _T("0") || str == _T("no") || str == _T("exclude"))
                                pfilter->default_include = false;
                        else if (str == _T("1") || str == _T("yes") || str == _T("include"))
@@ -236,13 +221,25 @@ FileFilter * FileFilterMgr::LoadFilterFile(const String& szFilepath, int & error
                {
                        // file filter
                        String str = sLine.substr(2);
-                       AddFilterPattern(&pfilter->filefilters, str);
+                       AddFilterPattern(&pfilter->filefilters, str, true);
                }
                else if (0 == sLine.compare(0, 2, _T("d:"), 2))
                {
                        // directory filter
                        String str = sLine.substr(2);
-                       AddFilterPattern(&pfilter->dirfilters, str);
+                       AddFilterPattern(&pfilter->dirfilters, str, false);
+               }
+               else if (0 == sLine.compare(0, 3, _T("f!:"), 3))
+               {
+                       // file filter
+                       String str = sLine.substr(3);
+                       AddFilterPattern(&pfilter->filefiltersExclude, str, true);
+               }
+               else if (0 == sLine.compare(0, 3, _T("d!:"), 3))
+               {
+                       // directory filter
+                       String str = sLine.substr(3);
+                       AddFilterPattern(&pfilter->dirfiltersExclude, str, false);
                }
        } while (bLinesLeft);
 
@@ -253,7 +250,7 @@ FileFilter * FileFilterMgr::LoadFilterFile(const String& szFilepath, int & error
  * @brief Give client back a pointer to the actual filter.
  *
  * @param [in] szFilterPath Full path to filterfile.
- * @return Pointer to found filefilter or NULL;
+ * @return Pointer to found filefilter or `nullptr`;
  * @note We just do a linear search, because this is seldom called
  */
 FileFilter * FileFilterMgr::GetFilterByPath(const String& szFilterPath)
@@ -261,7 +258,7 @@ FileFilter * FileFilterMgr::GetFilterByPath(const String& szFilterPath)
        vector<FileFilterPtr>::const_iterator iter = m_filters.begin();
        while (iter != m_filters.end())
        {
-               if (string_compare_nocase((*iter)->fullpath, szFilterPath) == 0)
+               if (strutils::compare_nocase((*iter)->fullpath, szFilterPath) == 0)
                        return (*iter).get();
                ++iter;
        }
@@ -269,6 +266,20 @@ FileFilter * FileFilterMgr::GetFilterByPath(const String& szFilterPath)
 }
 
 /**
+ * @brief Give client back a pointer to the actual filter.
+ *
+ * @param [in] i Index of filter.
+ * @return Pointer to filefilter in given index or `nullptr`.
+ */
+FileFilter * FileFilterMgr::GetFilterByIndex(int i)
+{
+       if (i < 0 || i >= m_filters.size())
+               return nullptr;
+
+       return m_filters[i].get();
+}
+
+/**
  * @brief Test given string against given regexp list.
  *
  * @param [in] filterList List of regexps to test against.
@@ -281,7 +292,7 @@ bool TestAgainstRegList(const vector<FileFilterElementPtr> *filterList, const St
        if (filterList->size() == 0)
                return false;
 
-       std::string compString;
+       std::string compString, compStringFileName;
        ucr::toUTF8(szTest, compString);
        vector<FileFilterElementPtr>::const_iterator iter = filterList->begin();
        while (iter != filterList->end())
@@ -289,7 +300,9 @@ bool TestAgainstRegList(const vector<FileFilterElementPtr> *filterList, const St
                RegularExpression::Match match;
                try
                {
-                       if ((*iter)->regexp.match(compString, 0, match) > 0)
+                       if ((*iter)->_fileNameOnly && compStringFileName.empty())
+                               ucr::toUTF8(paths::FindFileName(szTest), compStringFileName);
+                       if ((*iter)->regexp.match((*iter)->_fileNameOnly ? compStringFileName : compString, 0, match) > 0)
                                return true;
                }
                catch (...)
@@ -316,10 +329,13 @@ bool TestAgainstRegList(const vector<FileFilterElementPtr> *filterList, const St
 bool FileFilterMgr::TestFileNameAgainstFilter(const FileFilter * pFilter,
        const String& szFileName) const
 {
-       if (!pFilter)
+       if (pFilter == nullptr)
                return true;
        if (TestAgainstRegList(&pFilter->filefilters, szFileName))
-               return !pFilter->default_include;
+       {
+               if (pFilter->filefiltersExclude.empty() || !TestAgainstRegList(&pFilter->filefiltersExclude, szFileName))
+                       return !pFilter->default_include;
+       }
        return pFilter->default_include;
 }
 
@@ -337,78 +353,17 @@ bool FileFilterMgr::TestFileNameAgainstFilter(const FileFilter * pFilter,
 bool FileFilterMgr::TestDirNameAgainstFilter(const FileFilter * pFilter,
        const String& szDirName) const
 {
-       if (!pFilter)
+       if (pFilter == nullptr)
                return true;
        if (TestAgainstRegList(&pFilter->dirfilters, szDirName))
-               return !pFilter->default_include;
+       {
+               if (pFilter->dirfiltersExclude.empty() || !TestAgainstRegList(&pFilter->dirfiltersExclude, szDirName))
+                       return !pFilter->default_include;
+       }
        return pFilter->default_include;
 }
 
 /**
- * @brief Return name of filter.
- *
- * @param [in] i Index of filter.
- * @return Name of filter in given index.
- */
-String FileFilterMgr::GetFilterName(int i) const
-{
-       return m_filters[i]->name; 
-}
-
-/**
- * @brief Return name of filter.
- * @param [in] pFilter Filter to get name for.
- * @return Given filter's name.
- */
-String FileFilterMgr::GetFilterName(const FileFilter *pFilter) const
-{
-       return pFilter->name; 
-}
-
-/**
- * @brief Return description of filter.
- *
- * @param [in] i Index of filter.
- * @return Description of filter in given index.
- */
-String FileFilterMgr::GetFilterDesc(int i) const
-{
-       return m_filters[i]->description; 
-}
-
-/**
- * @brief Return description of filter.
- * @param [in] pFilter Filter to get description for.
- * @return Given filter's description.
- */
-String FileFilterMgr::GetFilterDesc(const FileFilter *pFilter) const
-{
-       return pFilter->description;
-}
-
-/**
- * @brief Return full path to filter.
- *
- * @param [in] i Index of filter.
- * @return Full path of filter in given index.
- */
-String FileFilterMgr::GetFilterPath(int i) const
-{
-       return m_filters[i]->fullpath;
-}
-
-/**
- * @brief Return full path to filter.
- *
- * @param [in] pFilter Pointer to filter.
- * @return Full path of filter.
- */
-String FileFilterMgr::GetFullpath(FileFilter * pfilter) const
-{
-       return pfilter->fullpath;
-}
-
-/**
  * @brief Reload filter from disk
  *
  * Reloads filter from disk. This is done by creating a new one
@@ -423,7 +378,7 @@ int FileFilterMgr::ReloadFilterFromDisk(FileFilter * pfilter)
        int errorcode = FILTER_OK;
        FileFilter * newfilter = LoadFilterFile(pfilter->fullpath, errorcode);
 
-       if (newfilter == NULL)
+       if (newfilter == nullptr)
        {
                return errorcode;
        }
@@ -459,3 +414,25 @@ int FileFilterMgr::ReloadFilterFromDisk(const String& szFullPath)
                errorcode = FILTER_NOTFOUND;
        return errorcode;
 }
+
+/**
+ * @brief Clone file filter manager from another file filter Manager.
+ * This function clones file filter manager from another file filter manager.
+ * Current contents in the file filter manager are removed and new contents added from the given file filter manager.
+ * @param [in] fileFilterManager File filter manager to clone.
+ */
+void FileFilterMgr::CloneFrom(const FileFilterMgr* fileFilterMgr)
+{
+       if (!fileFilterMgr)
+               return;
+
+       m_filters.clear();
+
+       size_t count = fileFilterMgr->m_filters.size();
+       for (size_t i = 0; i < count; i++)
+       {
+               auto ptr = std::make_shared<FileFilter>(FileFilter());
+               ptr->CloneFrom(fileFilterMgr->m_filters[i].get());
+               m_filters.push_back(ptr);
+       }
+}