| #include "cmStandardIncludes.h" |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include "cmSystemTools.h" |
| #include "cmParseGTMCoverage.h" |
| #include <cmsys/Directory.hxx> |
| #include <cmsys/Glob.hxx> |
| #include <cmsys/FStream.hxx> |
| |
| |
| cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, |
| cmCTest* ctest) |
| :cmParseMumpsCoverage(cont, ctest) |
| { |
| } |
| |
| |
| bool cmParseGTMCoverage::LoadCoverageData(const char* d) |
| { |
| // load all the .mcov files in the specified directory |
| cmsys::Directory dir; |
| if(!dir.Load(d)) |
| { |
| return false; |
| } |
| size_t numf; |
| unsigned int i; |
| numf = dir.GetNumberOfFiles(); |
| for (i = 0; i < numf; i++) |
| { |
| std::string file = dir.GetFile(i); |
| if(file != "." && file != ".." |
| && !cmSystemTools::FileIsDirectory(file.c_str())) |
| { |
| std::string path = d; |
| path += "/"; |
| path += file; |
| if(cmSystemTools::GetFilenameLastExtension(path) == ".mcov") |
| { |
| if(!this->ReadMCovFile(path.c_str())) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| bool cmParseGTMCoverage::ReadMCovFile(const char* file) |
| { |
| cmsys::ifstream in(file); |
| if(!in) |
| { |
| return false; |
| } |
| std::string line; |
| std::string lastfunction; |
| std::string lastroutine; |
| std::string lastpath; |
| int lastoffset = 0; |
| while( cmSystemTools::GetLineFromStream(in, line)) |
| { |
| // only look at lines that have coverage data |
| if(line.find("^ZZCOVERAGE") == line.npos) |
| { |
| continue; |
| } |
| std::string filepath; |
| std::string function; |
| std::string routine; |
| int linenumber = 0; |
| int count = 0; |
| this->ParseMCOVLine(line, routine, function, linenumber, count); |
| // skip this one |
| if(routine == "RSEL") |
| { |
| continue; |
| } |
| // no need to search the file if we just did it |
| if(function == lastfunction && lastroutine == routine) |
| { |
| if(lastpath.size()) |
| { |
| this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber] |
| += count; |
| } |
| else |
| { |
| cmCTestLog(this->CTest, ERROR_MESSAGE, |
| "Can not find mumps file : " |
| << lastroutine << |
| " referenced in this line of mcov data:\n" |
| "[" << line << "]\n"); |
| } |
| continue; |
| } |
| // Find the full path to the file |
| bool found = this->FindMumpsFile(routine, filepath); |
| if(found) |
| { |
| int lineoffset = 0; |
| if(this->FindFunctionInMumpsFile(filepath, |
| function, |
| lineoffset)) |
| { |
| cmCTestCoverageHandlerContainer::SingleFileCoverageVector& |
| coverageVector = this->Coverage.TotalCoverage[filepath]; |
| coverageVector[lineoffset + linenumber] += count; |
| lastoffset = lineoffset; |
| } |
| } |
| else |
| { |
| cmCTestLog(this->CTest, ERROR_MESSAGE, |
| "Can not find mumps file : " |
| << routine << " referenced in this line of mcov data:\n" |
| "[" << line << "]\n"); |
| } |
| lastfunction = function; |
| lastroutine = routine; |
| lastpath = filepath; |
| } |
| return true; |
| } |
| |
| bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath, |
| std::string const& function, |
| int& lineoffset) |
| { |
| cmsys::ifstream in(filepath.c_str()); |
| if(!in) |
| { |
| return false; |
| } |
| std::string line; |
| int linenum = 0; |
| while( cmSystemTools::GetLineFromStream(in, line)) |
| { |
| std::string::size_type pos = line.find(function.c_str()); |
| if(pos == 0) |
| { |
| char nextchar = line[function.size()]; |
| if(nextchar == ' ' || nextchar == '(') |
| { |
| lineoffset = linenum; |
| return true; |
| } |
| } |
| if(pos == 1) |
| { |
| char prevchar = line[0]; |
| char nextchar = line[function.size()+1]; |
| if(prevchar == '%' && (nextchar == ' ' || nextchar == '(')) |
| { |
| lineoffset = linenum; |
| return true; |
| } |
| } |
| linenum++; // move to next line count |
| } |
| lineoffset = 0; |
| cmCTestLog(this->CTest, ERROR_MESSAGE, |
| "Could not find entry point : " |
| << function << " in " << filepath << "\n"); |
| return false; |
| } |
| |
| bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line, |
| std::string& routine, |
| std::string& function, |
| int& linenumber, |
| int& count) |
| { |
| // this method parses lines from the .mcov file |
| // each line has ^COVERAGE(...) in it, and there |
| // are several varients of coverage lines: |
| // |
| // ^COVERAGE("DIC11","PR1",0)="2:0:0:0" |
| // ( file , entry, line ) = "number_executed:timing_info" |
| // ^COVERAGE("%RSEL","SRC")="1:0:0:0" |
| // ( file , entry ) = "number_executed:timing_info" |
| // ^COVERAGE("%RSEL","init",8,"FOR_LOOP",1)=1 |
| // ( file , entry, line, IGNORE ) =number_executed |
| std::vector<cmStdString> args; |
| std::string::size_type pos = line.find('(', 0); |
| // if no ( is found, then return line has no coverage |
| if(pos == std::string::npos) |
| { |
| return false; |
| } |
| std::string arg; |
| bool done = false; |
| // separate out all of the comma separated arguments found |
| // in the COVERAGE(...) line |
| while(line[pos] && !done) |
| { |
| // save the char we are looking at |
| char cur = line[pos]; |
| // , or ) means end of argument |
| if(cur == ',' || cur == ')') |
| { |
| // save the argument into the argument vector |
| args.push_back(arg); |
| // start on a new argument |
| arg = ""; |
| // if we are at the end of the ), then finish while loop |
| if(cur == ')') |
| { |
| done = true; |
| } |
| } |
| else |
| { |
| // all chars except ", (, and % get stored in the arg string |
| if(cur != '\"' && cur != '(' && cur != '%') |
| { |
| arg.append(1, line[pos]); |
| } |
| } |
| // move to next char |
| pos++; |
| } |
| // now parse the right hand side of the = |
| pos = line.find('='); |
| // no = found, this is an error |
| if(pos == line.npos) |
| { |
| return false; |
| } |
| pos++; // move past = |
| |
| // if the next positing is not a ", then this is a |
| // COVERAGE(..)=count line and turn the rest of the string |
| // past the = into an integer and set it to count |
| if(line[pos] != '\"') |
| { |
| count = atoi(line.substr(pos).c_str()); |
| } |
| else |
| { |
| // this means line[pos] is a ", and we have a |
| // COVERAGE(...)="1:0:0:0" type of line |
| pos++; // move past " |
| // find the first : past the " |
| std::string::size_type pos2 = line.find(':', pos); |
| // turn the string between the " and the first : into an integer |
| // and set it to count |
| count = atoi(line.substr(pos, pos2-pos).c_str()); |
| } |
| // less then two arguments is an error |
| if(args.size() < 2) |
| { |
| cmCTestLog(this->CTest, ERROR_MESSAGE, |
| "Error parsing mcov line: [" << line << "]\n"); |
| return false; |
| } |
| routine = args[0]; // the routine is the first argument |
| function = args[1]; // the function in the routine is the second |
| // in the two argument only format |
| // ^COVERAGE("%RSEL","SRC"), the line offset is 0 |
| if(args.size() == 2) |
| { |
| linenumber = 0; |
| } |
| else |
| { |
| // this is the format for this line |
| // ^COVERAGE("%RSEL","SRC",count) |
| linenumber = atoi(args[2].c_str()); |
| } |
| return true; |
| } |