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("");
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<std::string, std::string> code;
std::list<std::string> 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<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;
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() )

View File

@ -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<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..
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<std::string> cfgs = getcfgs( codestr );
// 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 );
}
resultConfigurations = getcfgs( processedFile );
}

View File

@ -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<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 */
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<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 );
};
//---------------------------------------------------------------------------