From c85090153694adc072d3d96c32645205a5b3827d Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Fri, 26 Dec 2008 22:52:27 +0000 Subject: [PATCH] Added preprocessor a way to retrieve configurations and file content one configuration at time, because large files could consume 500 MB or even more memory. --- cppcheck.cpp | 22 ++++++++++++-------- preprocessor.cpp | 53 +++++++++++++++++++++++------------------------- preprocessor.h | 28 +++++++++++++++++++++---- 3 files changed, 62 insertions(+), 41 deletions(-) diff --git a/cppcheck.cpp b/cppcheck.cpp index b452761f8..b99223533 100644 --- a/cppcheck.cpp +++ b/cppcheck.cpp @@ -144,29 +144,33 @@ void CppCheck::check() _errout.str(""); std::string fname = _filenames[c]; - // If only errors are printed, print filename after the check - if ( _settings._errorsOnly == false ) - _errorLogger->reportOut( std::string( "Checking " ) + fname + std::string( "..." ) ); Preprocessor preprocessor; - std::map code; + std::list configurations; + std::string filedata = ""; if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() ) { // File content was given as a string std::istringstream iss( _fileContents[ _filenames[c] ] ); - preprocessor.preprocess(iss, code, fname); + preprocessor.preprocess(iss, fname, filedata, configurations ); } else { // Only file name was given, read the content from file std::ifstream fin( fname.c_str() ); - preprocessor.preprocess(fin, code, fname); + preprocessor.preprocess(fin, fname, filedata, configurations ); } - for ( std::map::const_iterator it = code.begin(); it != code.end(); ++it ) + for ( std::list::const_iterator it = configurations.begin(); it != configurations.end(); ++it ) { - cfg = it->first; - checkFile(it->second, _filenames[c].c_str()); + cfg = *it; + std::string codeWithoutCfg = Preprocessor::getcode( filedata, *it ); + + // If only errors are printed, print filename after the check + if ( _settings._errorsOnly == false ) + _errorLogger->reportOut( std::string( "Checking " ) + fname + ": "+cfg+std::string( "..." ) ); + + checkFile( codeWithoutCfg, _filenames[c].c_str()); } if ( _settings._errorsOnly == false && _errout.str().empty() ) diff --git a/preprocessor.cpp b/preprocessor.cpp index 2c521d685..4ac81f582 100644 --- a/preprocessor.cpp +++ b/preprocessor.cpp @@ -140,55 +140,52 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename) return code.str(); } -/** - * Extract the code for each configuration - * \param istr The (file/string) stream to read from. - * \param result The map that will get the results - */ void Preprocessor::preprocess(std::istream &istr, std::map &result, const std::string &filename) { - std::string codestr( read(istr, filename) ); + std::list configs; + std::string data; + preprocess( istr, filename, data, configs ); + for ( std::list::const_iterator it = configs.begin(); it != configs.end(); ++it ) + result[ *it ] = Preprocessor::getcode( data, *it ); +} + +void Preprocessor::preprocess(std::istream &istr, const std::string &filename, std::string &processedFile, std::list &resultConfigurations) +{ + processedFile = read(istr, filename); // Replace all tabs with spaces.. std::string::size_type loc = 0; - while ( (loc = codestr.find("\t", loc)) != std::string::npos ) - codestr[loc] = ' '; + while ( (loc = processedFile.find("\t", loc)) != std::string::npos ) + processedFile[loc] = ' '; // Remove all indentation.. - if ( !codestr.empty() && codestr[0] == ' ' ) - codestr.erase( 0, codestr.find_first_not_of(" ") ); + if ( !processedFile.empty() && processedFile[0] == ' ' ) + processedFile.erase( 0, processedFile.find_first_not_of(" ") ); loc = 0; - while ( (loc = codestr.find("\n ", loc)) != std::string::npos ) - codestr.erase( 1 + loc, 1 ); + while ( (loc = processedFile.find("\n ", loc)) != std::string::npos ) + processedFile.erase( 1 + loc, 1 ); // Remove all trailing spaces.. loc = 0; - while ( (loc = codestr.find(" \n", loc)) != std::string::npos ) + while ( (loc = processedFile.find(" \n", loc)) != std::string::npos ) { - codestr.erase( loc, 1 ); + processedFile.erase( loc, 1 ); if ( loc > 0 ) --loc; } // Using the backslash at the end of a line.. - while ( (loc = codestr.rfind("\\\n")) != std::string::npos ) + while ( (loc = processedFile.rfind("\\\n")) != std::string::npos ) { - codestr.erase(loc, 2); - if (loc > 0 && codestr[loc-1] != ' ') - codestr.insert(loc, " "); - if ( (loc = codestr.find("\n", loc)) != std::string::npos) - codestr.insert( loc, "\n" ); + processedFile.erase(loc, 2); + if (loc > 0 && processedFile[loc-1] != ' ') + processedFile.insert(loc, " "); + if ( (loc = processedFile.find("\n", loc)) != std::string::npos) + processedFile.insert( loc, "\n" ); } // Get all possible configurations.. - std::list cfgs = getcfgs( codestr ); - - // Extract the code for each possible configuration.. - result.clear(); - for ( std::list::const_iterator it = cfgs.begin(); it != cfgs.end(); ++it ) - { - result[ *it ] = getcode( codestr, *it ); - } + resultConfigurations = getcfgs( processedFile ); } diff --git a/preprocessor.h b/preprocessor.h index f6f65477d..8424846e8 100644 --- a/preprocessor.h +++ b/preprocessor.h @@ -32,25 +32,45 @@ class Preprocessor public: Preprocessor(); + /** + * Extract the code for each configuration + * \param istr The (file/string) stream to read from. + * \param result The map that will get the results + */ void preprocess(std::istream &istr, std::map &result, const std::string &filename); + /** + * Extract the code for each configuration. Use this with getcode() to get the + * file data for each individual configuration. + * + * @param istr The (file/string) stream to read from. + * @param filename + * @param processedFile Give reference to empty string as a parameter, + * function will fill processed file here. Use this also as a filedata parameter + * to getcode() if you recieved more than once configurations. + * @param resultConfigurations List of configurations. Pass these one by one + * to getcode() with processedFile. + */ + void preprocess(std::istream &istr, const std::string &filename, std::string &processedFile, std::list &resultConfigurations ); + /** Just read the code into a string. Perform simple cleanup of the code */ std::string read(std::istream &istr, const std::string &filename); -private: /** * Get preprocessed code for a given configuration */ - std::string getcode(const std::string &filedata, std::string cfg); + static std::string getcode(const std::string &filedata, std::string cfg); + +private: /** * Get all possible configurations. By looking at the ifdefs and ifndefs in filedata */ std::list getcfgs( const std::string &filedata ); - std::string getdef(std::string line, bool def); + static std::string getdef(std::string line, bool def); - bool match_cfg_def( std::string cfg, const std::string &def ); + static bool match_cfg_def( std::string cfg, const std::string &def ); }; //---------------------------------------------------------------------------