From d1bbcf173434e3639d36e9938986c85d1de25be4 Mon Sep 17 00:00:00 2001 From: Kimmo Varis Date: Thu, 11 Mar 2010 21:58:59 +0200 Subject: [PATCH] Implement Win32 FileLister as separate class. Improve the system used to have separate versions of code of FileLister for Win32 and Linux. New idea is to have Base FileLister class implementing common code and then derived classes for Win32 and Linux specific code. FileLister is not anymore a static class. Instead we use singleton of derived class. --- cli/cppcheck.vcproj | 8 ++ gui/mainwindow.cpp | 2 +- lib/checkheaders.cpp | 2 +- lib/cppcheck.cpp | 4 +- lib/filelister.cpp | 13 +++ lib/filelister.h | 12 ++- lib/filelister_win32.cpp | 201 +++++++++++++++++++++++++++++++++++++++ lib/filelister_win32.h | 43 +++++++++ lib/lib.pri | 8 ++ lib/preprocessor.cpp | 2 +- lib/tokenize.cpp | 6 +- 11 files changed, 288 insertions(+), 13 deletions(-) create mode 100644 lib/filelister_win32.cpp create mode 100644 lib/filelister_win32.h diff --git a/cli/cppcheck.vcproj b/cli/cppcheck.vcproj index 9f49e54eb..fe7319d19 100755 --- a/cli/cppcheck.vcproj +++ b/cli/cppcheck.vcproj @@ -268,6 +268,10 @@ RelativePath="..\lib\filelister.cpp" > + + @@ -370,6 +374,10 @@ RelativePath="..\lib\filelister.h" > + + diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 6e92366c2..1508f62bb 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -379,7 +379,7 @@ QStringList MainWindow::RemoveUnacceptedFiles(const QStringList &list) QString str; foreach(str, list) { - if (FileLister::acceptFile(str.toStdString())) + if (getFileLister()->acceptFile(str.toStdString())) { result << str; } diff --git a/lib/checkheaders.cpp b/lib/checkheaders.cpp index 3125e3016..36c0cabbf 100644 --- a/lib/checkheaders.cpp +++ b/lib/checkheaders.cpp @@ -100,7 +100,7 @@ void CheckHeaders::warningIncludeHeader() const std::string includefile = includetok->strAt(1); while (hfile < _tokenizer->getFiles()->size()) { - if (FileLister::sameFileName(_tokenizer->getFiles()->at(hfile), includefile)) + if (getFileLister()->sameFileName(_tokenizer->getFiles()->at(hfile), includefile)) break; ++hfile; } diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 33c47e3ec..e9e8d5119 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -61,7 +61,7 @@ void CppCheck::settings(const Settings &settings) void CppCheck::addFile(const std::string &path) { - FileLister::recursiveAddFiles(_filenames, path.c_str(), true); + getFileLister()->recursiveAddFiles(_filenames, path.c_str(), true); } void CppCheck::addFile(const std::string &path, const std::string &content) @@ -373,7 +373,7 @@ void CppCheck::parseFromArgs(int argc, const char* const argv[]) // Execute recursiveAddFiles() to each given file parameter std::vector::const_iterator iter; for (iter = pathnames.begin(); iter != pathnames.end(); ++iter) - FileLister::recursiveAddFiles(_filenames, iter->c_str(), true); + getFileLister()->recursiveAddFiles(_filenames, iter->c_str(), true); } if (argc <= 1 || showHelp) diff --git a/lib/filelister.cpp b/lib/filelister.cpp index 615dcdce0..1aa7da105 100644 --- a/lib/filelister.cpp +++ b/lib/filelister.cpp @@ -17,6 +17,7 @@ */ #include "filelister.h" +#include "fileLister_win32.h" #include #include #include @@ -34,6 +35,18 @@ #include #endif +static FileLister *fileLister; + +FileLister * getFileLister() +{ + if (fileLister == NULL) + { + fileLister = new FileListerWin32; + return fileLister; + } + return fileLister; +} + std::string FileLister::simplifyPath(const char *originalPath) { std::string subPath = ""; diff --git a/lib/filelister.h b/lib/filelister.h index 181c5840a..879fa839c 100644 --- a/lib/filelister.h +++ b/lib/filelister.h @@ -29,14 +29,16 @@ class FileLister { public: - static void recursiveAddFiles(std::vector &filenames, const std::string &path, bool recursive); - static std::string simplifyPath(const char *originalPath); - static bool sameFileName(const std::string &fname1, const std::string &fname2); - static bool acceptFile(const std::string &filename); + virtual void recursiveAddFiles(std::vector &filenames, const std::string &path, bool recursive); + virtual std::string simplifyPath(const char *originalPath); + virtual bool sameFileName(const std::string &fname1, const std::string &fname2); + virtual bool acceptFile(const std::string &filename); private: }; +FileLister * getFileLister(); + /// @} -#endif // #ifndef FILELISTER_H +#endif // #ifndef FileListerH diff --git a/lib/filelister_win32.cpp b/lib/filelister_win32.cpp new file mode 100644 index 000000000..8ef5b37ad --- /dev/null +++ b/lib/filelister_win32.cpp @@ -0,0 +1,201 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. + * + * 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 3 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, see . + */ + +#include "filelister_win32.h" +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#ifndef __BORLANDC__ +#include +#endif +#endif + + + + + +/////////////////////////////////////////////////////////////////////////////// +////// This code is for Microsoft Windows ///////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_WIN32) + +// Here is the catch: cppcheck core is Ansi code (using char type). +// When compiling Unicode targets WinAPI automatically uses *W Unicode versions +// of called functions. So we must convert data given to WinAPI functions from +// ANSI to Unicode. Likewise we must convert data we get from WinAPI from +// Unicode to ANSI. + +#if defined(UNICODE) + +static bool TransformUcs2ToAnsi(LPCWSTR psUcs, LPSTR psAnsi, int nAnsi) +{ + WideCharToMultiByte(CP_ACP, 0, psUcs, -1, psAnsi, nAnsi, NULL, NULL); + return true; +} + +static bool TransformAnsiToUcs2(LPCSTR psAnsi, LPWSTR psUcs, UINT nUcs) +{ + MultiByteToWideChar(CP_ACP, 0, psAnsi, -1, psUcs, nUcs); + return true; +} + +static BOOL MyIsDirectory(std::string path) +{ + WCHAR * unicodeCleanPath = new WCHAR[path.size() + 1]; + TransformAnsiToUcs2(path.c_str(), unicodeCleanPath, + (path.size() * sizeof(WCHAR)) + 1); + // See http://msdn.microsoft.com/en-us/library/bb773621(VS.85).aspx + BOOL res = PathIsDirectory(unicodeCleanPath); + delete [] unicodeCleanPath; + return res; +} + +static HANDLE MyFindFirstFile(std::string path, LPWIN32_FIND_DATA findData) +{ + WCHAR * unicodeOss = new wchar_t[path.size() + 1]; + TransformAnsiToUcs2(path.c_str(), unicodeOss, (path.size() + 1) * sizeof(WCHAR)); + HANDLE hFind = FindFirstFile(unicodeOss, findData); + delete [] unicodeOss; + return hFind; +} + +#else // defined(UNICODE) + +static BOOL MyIsDirectory(std::string path) +{ +#ifdef __BORLANDC__ + return (GetFileAttributes(path.c_str()) & FILE_ATTRIBUTE_DIRECTORY); +#else +// See http://msdn.microsoft.com/en-us/library/bb773621(VS.85).aspx +return PathIsDirectory(path.c_str()); +#endif +} + +static HANDLE MyFindFirstFile(std::string path, LPWIN32_FIND_DATA findData) +{ + HANDLE hFind = FindFirstFile(path.c_str(), findData); + return hFind; +} + +#endif // defined(UNICODE) + +void FileListerWin32::recursiveAddFiles(std::vector &filenames, const std::string &path, bool recursive) +{ + // oss is the search string passed into FindFirst and FindNext. + // bdir is the base directory which is used to form pathnames. + // It always has a trailing backslash available for concatenation. + std::ostringstream bdir, oss; + + std::string cleanedPath = path; + std::replace(cleanedPath.begin(), cleanedPath.end(), '/', '\\'); + + oss << cleanedPath; + + if (MyIsDirectory(cleanedPath.c_str())) + { + char c = cleanedPath[ cleanedPath.size()-1 ]; + switch (c) + { + case '\\': + oss << '*'; + bdir << cleanedPath; + break; + case '*': + bdir << cleanedPath.substr(0, cleanedPath.length() - 1); + break; + default: + oss << "\\*"; + bdir << cleanedPath << '\\'; + } + } + else + { + std::string::size_type pos; + pos = cleanedPath.find_last_of('\\'); + if (std::string::npos != pos) + { + bdir << cleanedPath.substr(0, pos + 1); + } + } + + WIN32_FIND_DATA ffd; + HANDLE hFind = MyFindFirstFile(oss.str(), &ffd); + if (INVALID_HANDLE_VALUE == hFind) + return; + + do + { + if (ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0') + continue; + +#if defined(UNICODE) + char * ansiFfd = new char[wcslen(ffd.cFileName) + 1]; + TransformUcs2ToAnsi(ffd.cFileName, ansiFfd, wcslen(ffd.cFileName) + 1); +#else // defined(UNICODE) + char * ansiFfd = &ffd.cFileName[0]; +#endif // defined(UNICODE) + + std::ostringstream fname; + fname << bdir.str().c_str() << ansiFfd; + + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + { + // File + + // If recursive is not used, accept all files given by user + if (!recursive || FileLister::acceptFile(ansiFfd)) + filenames.push_back(fname.str()); + } + else if (recursive) + { + // Directory + FileLister::recursiveAddFiles(filenames, fname.str().c_str(), recursive); + } +#if defined(UNICODE) + delete [] ansiFfd; +#endif // defined(UNICODE) + } + while (FindNextFile(hFind, &ffd) != FALSE); + + if (INVALID_HANDLE_VALUE != hFind) + { + FindClose(hFind); + hFind = INVALID_HANDLE_VALUE; + } +} + +#endif + +//--------------------------------------------------------------------------- + +bool FileListerWin32::sameFileName(const std::string &fname1, const std::string &fname2) +{ +#ifdef __BORLANDC__ + return bool(stricmp(fname1.c_str(), fname2.c_str()) == 0); +#endif +#ifdef _MSC_VER + return bool(_stricmp(fname1.c_str(), fname2.c_str()) == 0); +#endif +} diff --git a/lib/filelister_win32.h b/lib/filelister_win32.h new file mode 100644 index 000000000..467ccca0d --- /dev/null +++ b/lib/filelister_win32.h @@ -0,0 +1,43 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team. + * + * 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 3 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, see . + */ + +#ifndef FileListerWin32H +#define FileListerWin32H + +#include +#include +#include "filelister.h" + +/// @addtogroup Core +/// @{ + + +class FileListerWin32 : public FileLister +{ +public: + virtual void recursiveAddFiles(std::vector &filenames, const std::string &path, bool recursive); +// virtual static std::string simplifyPath(const char *originalPath); + virtual bool sameFileName(const std::string &fname1, const std::string &fname2); +// virtual static bool acceptFile(const std::string &filename); +private: + +}; + +/// @} + +#endif // #ifndef FileListerWin32H diff --git a/lib/lib.pri b/lib/lib.pri index 24e2ca24e..d56336bbb 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -21,6 +21,10 @@ HEADERS += $$PWD/check.h \ $$PWD/token.h \ $$PWD/tokenize.h +win32 { +HEADERS += $$PWD/filelister_win32.h +} + SOURCES += $$PWD/checkautovariables.cpp \ $$PWD/checkbufferoverrun.cpp \ $$PWD/checkclass.cpp \ @@ -40,3 +44,7 @@ SOURCES += $$PWD/checkautovariables.cpp \ $$PWD/settings.cpp \ $$PWD/token.cpp \ $$PWD/tokenize.cpp + +win32 { +SOURCES += $$PWD/filelister_win32.cpp +} diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 5f296e730..df960aea2 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -1325,7 +1325,7 @@ void Preprocessor::handleIncludes(std::string &code, const std::string &filename if (fileOpened) { - std::string tempFile = FileLister::simplifyPath(filename.c_str()); + std::string tempFile = getFileLister()->simplifyPath(filename.c_str()); std::transform(tempFile.begin(), tempFile.end(), tempFile.begin(), tolowerWrapper); if (handledFiles.find(tempFile) != handledFiles.end()) { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 30ded2a40..289778808 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -230,7 +230,7 @@ void Tokenizer::createTokens(std::istream &code) fileIndexes.push_back(FileIndex); for (unsigned int i = 0; i < _files.size(); i++) { - if (FileLister::sameFileName(_files[i].c_str(), line.c_str())) + if (getFileLister()->sameFileName(_files[i].c_str(), line.c_str())) { // Use this index foundOurfile = true; @@ -241,7 +241,7 @@ void Tokenizer::createTokens(std::istream &code) if (!foundOurfile) { // The "_files" vector remembers what files have been tokenized.. - _files.push_back(FileLister::simplifyPath(line.c_str())); + _files.push_back(getFileLister()->simplifyPath(line.c_str())); FileIndex = static_cast(_files.size() - 1); } @@ -1094,7 +1094,7 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[], const std::s _configuration = configuration; // The "_files" vector remembers what files have been tokenized.. - _files.push_back(FileLister::simplifyPath(FileName)); + _files.push_back(getFileLister()->simplifyPath(FileName)); createTokens(code);