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.

This commit is contained in:
Reijo Tomperi 2008-12-26 22:52:27 +00:00
parent 6ef11f3f49
commit c850901536
3 changed files with 62 additions and 41 deletions

View File

@ -144,29 +144,33 @@ void CppCheck::check()
_errout.str(""); _errout.str("");
std::string fname = _filenames[c]; 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; Preprocessor preprocessor;
std::map<std::string, std::string> code; std::list<std::string> configurations;
std::string filedata = "";
if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() ) if( _fileContents.size() > 0 && _fileContents.find( _filenames[c] ) != _fileContents.end() )
{ {
// File content was given as a string // File content was given as a string
std::istringstream iss( _fileContents[ _filenames[c] ] ); std::istringstream iss( _fileContents[ _filenames[c] ] );
preprocessor.preprocess(iss, code, fname); preprocessor.preprocess(iss, fname, filedata, configurations );
} }
else else
{ {
// Only file name was given, read the content from file // Only file name was given, read the content from file
std::ifstream fin( fname.c_str() ); std::ifstream fin( fname.c_str() );
preprocessor.preprocess(fin, code, fname); preprocessor.preprocess(fin, fname, filedata, configurations );
} }
for ( std::map<std::string,std::string>::const_iterator it = code.begin(); it != code.end(); ++it ) for ( std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it )
{ {
cfg = it->first; cfg = *it;
checkFile(it->second, _filenames[c].c_str()); 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() ) if ( _settings._errorsOnly == false && _errout.str().empty() )

View File

@ -140,55 +140,52 @@ std::string Preprocessor::read(std::istream &istr, const std::string &filename)
return code.str(); 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<std::string, std::string> &result, const std::string &filename) void Preprocessor::preprocess(std::istream &istr, std::map<std::string, std::string> &result, const std::string &filename)
{ {
std::string codestr( read(istr, filename) ); std::list<std::string> configs;
std::string data;
preprocess( istr, filename, data, configs );
for ( std::list<std::string>::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<std::string> &resultConfigurations)
{
processedFile = read(istr, filename);
// Replace all tabs with spaces.. // Replace all tabs with spaces..
std::string::size_type loc = 0; std::string::size_type loc = 0;
while ( (loc = codestr.find("\t", loc)) != std::string::npos ) while ( (loc = processedFile.find("\t", loc)) != std::string::npos )
codestr[loc] = ' '; processedFile[loc] = ' ';
// Remove all indentation.. // Remove all indentation..
if ( !codestr.empty() && codestr[0] == ' ' ) if ( !processedFile.empty() && processedFile[0] == ' ' )
codestr.erase( 0, codestr.find_first_not_of(" ") ); processedFile.erase( 0, processedFile.find_first_not_of(" ") );
loc = 0; loc = 0;
while ( (loc = codestr.find("\n ", loc)) != std::string::npos ) while ( (loc = processedFile.find("\n ", loc)) != std::string::npos )
codestr.erase( 1 + loc, 1 ); processedFile.erase( 1 + loc, 1 );
// Remove all trailing spaces.. // Remove all trailing spaces..
loc = 0; 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 ) if ( loc > 0 )
--loc; --loc;
} }
// Using the backslash at the end of a line.. // 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); processedFile.erase(loc, 2);
if (loc > 0 && codestr[loc-1] != ' ') if (loc > 0 && processedFile[loc-1] != ' ')
codestr.insert(loc, " "); processedFile.insert(loc, " ");
if ( (loc = codestr.find("\n", loc)) != std::string::npos) if ( (loc = processedFile.find("\n", loc)) != std::string::npos)
codestr.insert( loc, "\n" ); processedFile.insert( loc, "\n" );
} }
// Get all possible configurations.. // Get all possible configurations..
std::list<std::string> cfgs = getcfgs( codestr ); resultConfigurations = getcfgs( processedFile );
// Extract the code for each possible configuration..
result.clear();
for ( std::list<std::string>::const_iterator it = cfgs.begin(); it != cfgs.end(); ++it )
{
result[ *it ] = getcode( codestr, *it );
}
} }

View File

@ -32,25 +32,45 @@ class Preprocessor
public: public:
Preprocessor(); 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<std::string, std::string> &result, const std::string &filename); void preprocess(std::istream &istr, std::map<std::string, std::string> &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<std::string> &resultConfigurations );
/** Just read the code into a string. Perform simple cleanup of the code */ /** Just read the code into a string. Perform simple cleanup of the code */
std::string read(std::istream &istr, const std::string &filename); std::string read(std::istream &istr, const std::string &filename);
private:
/** /**
* Get preprocessed code for a given configuration * 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 * Get all possible configurations. By looking at the ifdefs and ifndefs in filedata
*/ */
std::list<std::string> getcfgs( const std::string &filedata ); std::list<std::string> 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 );
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------