|
Cppcheck
|
00001 /* 00002 * Cppcheck - A tool for static C/C++ code analysis 00003 * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team. 00004 * 00005 * This program is free software: you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation, either version 3 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include <cstring> 00020 #include <string> 00021 #include <sstream> 00022 #include "filelister.h" 00023 #include "path.h" 00024 00025 00026 #ifdef _WIN32 00027 00028 /////////////////////////////////////////////////////////////////////////////// 00029 ////// This code is WIN32 systems ///////////////////////////////////////////// 00030 /////////////////////////////////////////////////////////////////////////////// 00031 00032 #include <windows.h> 00033 #ifndef __BORLANDC__ 00034 #include <shlwapi.h> 00035 #endif 00036 00037 // Here is the catch: cppcheck core is Ansi code (using char type). 00038 // When compiling Unicode targets WinAPI automatically uses *W Unicode versions 00039 // of called functions. Thus, we explicitly call *A versions of the functions. 00040 00041 static BOOL MyIsDirectory(const std::string& path) 00042 { 00043 #ifdef __BORLANDC__ 00044 return (GetFileAttributes(path.c_str()) & FILE_ATTRIBUTE_DIRECTORY); 00045 #else 00046 // See http://msdn.microsoft.com/en-us/library/bb773621(VS.85).aspx 00047 return PathIsDirectoryA(path.c_str()); 00048 #endif 00049 } 00050 00051 static HANDLE MyFindFirstFile(const std::string& path, LPWIN32_FIND_DATAA findData) 00052 { 00053 HANDLE hFind = FindFirstFileA(path.c_str(), findData); 00054 return hFind; 00055 } 00056 00057 static BOOL MyFileExists(const std::string& path) 00058 { 00059 #ifdef __BORLANDC__ 00060 DWORD fa = GetFileAttributes(path.c_str()); 00061 BOOL result = FALSE; 00062 if (fa != INVALID_FILE_ATTRIBUTES && !(fa & FILE_ATTRIBUTE_DIRECTORY)) 00063 result = TRUE; 00064 #else 00065 BOOL result = PathFileExistsA(path.c_str()); 00066 #endif 00067 return result; 00068 } 00069 00070 void FileLister::recursiveAddFiles(std::map<std::string, std::size_t> &files, const std::string &path) 00071 { 00072 const std::string cleanedPath = Path::toNativeSeparators(path); 00073 00074 // basedir is the base directory which is used to form pathnames. 00075 // It always has a trailing backslash available for concatenation. 00076 std::string basedir; 00077 00078 // searchPattern is the search string passed into FindFirst and FindNext. 00079 std::string searchPattern = cleanedPath; 00080 00081 // The user wants to check all files in a dir 00082 const bool checkAllFilesInDir = (MyIsDirectory(cleanedPath) != FALSE); 00083 00084 if (checkAllFilesInDir) { 00085 char c = cleanedPath[ cleanedPath.size()-1 ]; 00086 switch (c) { 00087 case '\\': 00088 searchPattern += '*'; 00089 basedir = cleanedPath; 00090 break; 00091 case '*': 00092 basedir = cleanedPath.substr(0, cleanedPath.length() - 1); 00093 break; 00094 default: 00095 searchPattern += "\\*"; 00096 if (cleanedPath != ".") 00097 basedir = cleanedPath + '\\'; 00098 } 00099 } else { 00100 std::string::size_type pos = cleanedPath.find_last_of('\\'); 00101 if (std::string::npos != pos) { 00102 basedir = cleanedPath.substr(0, pos + 1); 00103 } 00104 } 00105 00106 WIN32_FIND_DATAA ffd; 00107 HANDLE hFind = MyFindFirstFile(searchPattern, &ffd); 00108 if (INVALID_HANDLE_VALUE == hFind) 00109 return; 00110 00111 do { 00112 if (ffd.cFileName[0] == '.' || ffd.cFileName[0] == '\0') 00113 continue; 00114 00115 const char* ansiFfd = ffd.cFileName; 00116 if (strchr(ansiFfd,'?')) { 00117 ansiFfd = ffd.cAlternateFileName; 00118 } 00119 00120 const std::string fname(basedir + ansiFfd); 00121 00122 if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { 00123 // File 00124 const std::string nativename = Path::fromNativeSeparators(fname); 00125 00126 if (!checkAllFilesInDir || Path::acceptFile(fname)) { 00127 // Limitation: file sizes are assumed to fit in a 'size_t' 00128 #ifdef _WIN64 00129 files[nativename] = (static_cast<std::size_t>(ffd.nFileSizeHigh) << 32) | ffd.nFileSizeLow; 00130 #else 00131 files[nativename] = ffd.nFileSizeLow; 00132 #endif 00133 } 00134 } else { 00135 // Directory 00136 FileLister::recursiveAddFiles(files, fname); 00137 } 00138 } while (FindNextFileA(hFind, &ffd) != FALSE); 00139 00140 if (INVALID_HANDLE_VALUE != hFind) { 00141 FindClose(hFind); 00142 } 00143 } 00144 00145 bool FileLister::isDirectory(const std::string &path) 00146 { 00147 return (MyIsDirectory(path) != FALSE); 00148 } 00149 00150 bool FileLister::fileExists(const std::string &path) 00151 { 00152 return (MyFileExists(path) == TRUE); 00153 } 00154 00155 00156 #else 00157 00158 /////////////////////////////////////////////////////////////////////////////// 00159 ////// This code is POSIX-style systems /////////////////////////////////////// 00160 /////////////////////////////////////////////////////////////////////////////// 00161 00162 #include <glob.h> 00163 #include <unistd.h> 00164 #include <stdlib.h> 00165 #include <limits.h> 00166 #include <sys/stat.h> 00167 00168 // Get absolute path. Returns empty string if path does not exist or other error. 00169 std::string FileLister::getAbsolutePath(const std::string& path) 00170 { 00171 std::string absolute_path; 00172 00173 #ifdef PATH_MAX 00174 char buf[PATH_MAX]; 00175 if (realpath(path.c_str(), buf) != NULL) 00176 absolute_path = buf; 00177 #else 00178 char *dynamic_buf; 00179 if ((dynamic_buf = realpath(path.c_str(), NULL)) != NULL) { 00180 absolute_path = dynamic_buf; 00181 free(dynamic_buf); 00182 } 00183 #endif 00184 00185 return absolute_path; 00186 } 00187 00188 void FileLister::recursiveAddFiles2(std::set<std::string> &seen_paths, 00189 std::map<std::string, std::size_t> &files, 00190 const std::string &path) 00191 { 00192 std::ostringstream oss; 00193 oss << path; 00194 if (path.length() > 0 && path[path.length()-1] == '/') 00195 oss << "*"; 00196 00197 glob_t glob_results; 00198 glob(oss.str().c_str(), GLOB_MARK, 0, &glob_results); 00199 for (unsigned int i = 0; i < glob_results.gl_pathc; i++) { 00200 const std::string filename = glob_results.gl_pathv[i]; 00201 if (filename == "." || filename == ".." || filename.length() == 0) 00202 continue; 00203 00204 // Determine absolute path. Empty filename if path does not exist 00205 const std::string absolute_path = getAbsolutePath(filename); 00206 if (absolute_path.empty()) 00207 continue; 00208 00209 // Did we already process this entry? 00210 if (seen_paths.find(absolute_path) != seen_paths.end()) 00211 continue; 00212 00213 if (filename[filename.length()-1] != '/') { 00214 // File 00215 00216 if (Path::sameFileName(path,filename) || Path::acceptFile(filename)) { 00217 seen_paths.insert(absolute_path); 00218 00219 struct stat sb; 00220 if (stat(absolute_path.c_str(), &sb) == 0) { 00221 // Limitation: file sizes are assumed to fit in a 'size_t' 00222 files[filename] = static_cast<std::size_t>(sb.st_size); 00223 } else 00224 files[filename] = 0; 00225 } 00226 } else { 00227 // Directory 00228 00229 seen_paths.insert(absolute_path); 00230 recursiveAddFiles2(seen_paths, files, filename); 00231 } 00232 } 00233 globfree(&glob_results); 00234 } 00235 00236 00237 void FileLister::recursiveAddFiles(std::map<std::string, std::size_t> &files, const std::string &path) 00238 { 00239 std::set<std::string> seen_paths; 00240 recursiveAddFiles2(seen_paths, files, path); 00241 } 00242 00243 bool FileLister::isDirectory(const std::string &path) 00244 { 00245 bool ret = false; 00246 00247 glob_t glob_results; 00248 glob(path.c_str(), GLOB_MARK, 0, &glob_results); 00249 if (glob_results.gl_pathc == 1) { 00250 const std::string glob_path = glob_results.gl_pathv[0]; 00251 if (!glob_path.empty() && glob_path[glob_path.size() - 1] == '/') { 00252 ret = true; 00253 } 00254 } 00255 globfree(&glob_results); 00256 00257 return ret; 00258 } 00259 00260 bool FileLister::fileExists(const std::string &path) 00261 { 00262 struct stat statinfo; 00263 int result = stat(path.c_str(), &statinfo); 00264 00265 if (result < 0) { // Todo: should check errno == ENOENT? 00266 // File not found 00267 return false; 00268 } 00269 00270 // Check if file is regular file 00271 if ((statinfo.st_mode & S_IFMT) == S_IFREG) 00272 return true; 00273 00274 return false; 00275 } 00276 00277 #endif
1.7.6.1