最近在找工作,某公司出了这么个题:统计项目源代码行数。
为了实现跨平台用了boost,g++和vs2010编译通过。代码如下:
FileTravel.h
#pragma once
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class FileTravel
{
public:
FileTravel(void);
FileTravel(const string& dirpath);
~FileTravel(void);
void SetFilterTypes(const vector<string> filtertypes);
bool IsFilterFile(const string &filepath);
void GetSubfiles(vector<string> & subfilepaths);
private:
string _dirpath; //源文件目录
vector<string> _subfilepaths; //源文件目录下的所有源文件路径
vector<string> _filterTypes; //后缀名过滤源文件类型
};
FileTravel.cpp
#include "FileTravel.h"
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
FileTravel::FileTravel(void)
: _dirpath(NULL)
{
_filterTypes.clear();
_subfilepaths.clear();
}
FileTravel::~FileTravel(void)
{
}
FileTravel::FileTravel(const string& dirpath)
: _dirpath(dirpath)
{
}
/*
获取源文件目录下的所有代码源文件
*/
void FileTravel::GetSubfiles(vector<string> & subfilepaths)
{
namespace fs = boost::filesystem;
fs::path rootpath(_dirpath, fs::native);
if(!fs::exists(rootpath))
return;
fs::recursive_directory_iterator endIter;
for(fs::recursive_directory_iterator iter(rootpath); iter != endIter; iter++) {
try{
if(fs::is_regular_file(*iter)){
if(IsFilterFile(iter->path().string())) {
subfilepaths.push_back(iter->path().string());
cout << *iter << " is a file" << std::endl;
}
}
} catch ( const std::exception & ex ){
std::cerr << ex.what() << std::endl;
continue;
}
}
}
void FileTravel::SetFilterTypes(const vector<string> filtertypes)
{
_filterTypes.clear();
_filterTypes.assign(filtertypes.begin(),filtertypes.end());
}
/*
过滤,判断是否是_filterTypes后缀的源文件类型
*/
bool FileTravel::IsFilterFile(const string &filepath)
{
if(_filterTypes.size() == 0)
return false;
vector<string>::iterator iter = _filterTypes.begin();
int len = filepath.length();
while( iter != _filterTypes.end() && filepath.rfind(*iter) != len-(*iter).length())
iter++;
if(iter == _filterTypes.end())
return false;
return true;
}
SourceLine.h
#pragma once
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <string>
#include <vector>
using namespace boost;
using namespace std;
typedef enum linetype {
NOTYPE_LINE, //在空行、注释行、代码行类型之外的类型
EMPTY_LINE, //空行
CODE_LINE, //代码行
NOTE_SINGLE_LINE, //单行注释
NOTE_MULTI_LINE //多行注释
}linetype;
typedef struct noteString{
string singlenotestr;
string multnote_startstr;
string multnote_endstr;
noteString()
{
}
noteString(const noteString& notestr)
{
singlenotestr = notestr.singlenotestr;
multnote_startstr = notestr.multnote_startstr;
multnote_endstr = notestr.multnote_endstr;
}
}noteString;
class SourceLine
{
public:
SourceLine(void);
SourceLine(const vector<string>& filepaths, int start, int end);
static unsigned long GetTotallines(void);
static unsigned long GetEmptylines(void);
static unsigned long GetNotelines(void);
static unsigned long GetValidCodelines(void);
void CalculateLine(void);
void SetNoteString(const noteString& notestr);
~SourceLine(void);
private:
static void incLine(linetype tp);
linetype analyisLine(string& line);
void calculateLine_singlefile(const string &filepath);
void setNoteString();
vector<string> _filepaths;
static unsigned long _emplines;//空行
static unsigned long _notelines;//注释行
static unsigned long _codelines;//有效代码行
noteString _notestr;
};
SourceLine.cpp
#include "SourceLine.h"
#include <exception>
#include <fstream>
#include <boost/algorithm/string.hpp>
unsigned long SourceLine::_codelines = 0;
unsigned long SourceLine::_emplines = 0;
unsigned long SourceLine::_notelines = 0;
mutex emplineMutex;
mutex codelineMutex;
mutex notelineMutex;
unsigned long SourceLine::GetTotallines()
{
unsigned long ret = GetEmptylines() + GetNotelines() + GetValidCodelines();
return ret;
}
unsigned long SourceLine::GetEmptylines()
{
mutex::scoped_lock lock(emplineMutex);
return _emplines;
}
unsigned long SourceLine::GetNotelines()
{
mutex::scoped_lock lock(notelineMutex);
return _notelines;
}
unsigned long SourceLine::GetValidCodelines()
{
mutex::scoped_lock lock(codelineMutex);
return _codelines;
}
void SourceLine::incLine(linetype tp)
{
switch (tp)
{
case EMPTY_LINE:
{
mutex::scoped_lock lock(emplineMutex);
++ _emplines;
}
break;
case NOTE_MULTI_LINE:
case NOTE_SINGLE_LINE:
{
mutex::scoped_lock lock(notelineMutex);
++ _notelines;
}
break;
case CODE_LINE:
{
mutex::scoped_lock lock (codelineMutex);
++ _codelines;
}
break;
default:
cout<<"warning: undefined line type"<<endl;
break;
}
}
SourceLine::SourceLine()
{
_filepaths.clear();
setNoteString();
}
SourceLine::SourceLine(const vector<string> & filepaths, int start, int end)
{
try
{
_filepaths.assign(filepaths.begin()+start, filepaths.begin()+end);
}
catch (const std::exception& e)
{
_filepaths.clear();
cerr<<"error SourceLine construction"<<e.what()<<endl;
}
setNoteString();
}
SourceLine::~SourceLine()
{
}
void SourceLine::setNoteString()
{
noteString notestr;
notestr.singlenotestr = "//";
notestr.multnote_startstr = "/*";
notestr.multnote_endstr = "*/";
_notestr = notestr;
}
void SourceLine::SetNoteString(const noteString& notestr)
{
_notestr = notestr;
}
/*
遍历所有源文件,计算行数
*/
void SourceLine::CalculateLine()
{
vector<string>::iterator iter = _filepaths.begin();
for(; iter != _filepaths.end(); iter++)
calculateLine_singlefile(*iter);
}
/*
计算单个源文件的各种行数
*/
void SourceLine::calculateLine_singlefile(const string &filepath)
{
ifstream fin;
string line;
linetype type;
int pos;
fin.open(filepath.c_str(), ios::in);
if(!fin) {
cerr<<"error open "<<filepath<<endl;
return;
}
do
{
getline(fin,line);
type = analyisLine(line);
/*
处理“/*xsfa*/ /*dd*”多行注释的不规范写法
*/
while(type == NOTE_MULTI_LINE) {
while(!contains(line, _notestr.multnote_endstr) && !fin.eof()) {
getline(fin,line);
incLine(NOTE_MULTI_LINE);
}
if((pos = line.find(_notestr.multnote_endstr)) == string::npos) {
cerr<<"error,invalid mutipleNote line in file."<<filepath<<endl;
return;
}
line = line.substr(pos+(_notestr.multnote_endstr).length());
trim(line);
if(contains(line, _notestr.multnote_startstr))
type = NOTE_MULTI_LINE;
else
type = NOTYPE_LINE;
}//while(type == NOTE_MULTI_LINE)
} while (!fin.eof());
}
/*
处理每一行,一行分为三种情况:
1.空行
2.以有效代码开头的判为代码行
3.以//或/*开头的判为注释行
*/
linetype SourceLine::analyisLine(string& linestr)
{
linetype type;
trim(linestr);
if(0 == linestr.length())
type = EMPTY_LINE;
else {
if(starts_with(linestr, _notestr.singlenotestr/*"//"*/) || starts_with(linestr, _notestr.multnote_startstr/*"/*"*/))
type = NOTE_SINGLE_LINE;
else
type = CODE_LINE;
}
incLine(type);
if(contains(linestr, _notestr.multnote_startstr/*"/*"*/))
type = NOTE_MULTI_LINE;
return type;
}
main.cpp
#include "SourceLine.h"
#include "FileTravel.h"
#include <sstream>
#include <list>
// 命令行参数:文件夹 线程数
int main(int argc, char* argv[])
{
if(argc < 3) {
cout<<"please intput a directory and a number as parameters."<<endl;
return 0;
}
// 1. 源文件所在的路径
FileTravel ft(argv[1]);
vector<string> filepaths;
vector<string> filtertypes;
//2. 自定义代码源文件类型,如c++的.cpp或java的.java
filtertypes.push_back(".h");
filtertypes.push_back(".cpp");
filtertypes.push_back(".hpp");
filtertypes.push_back(".c");
ft.SetFilterTypes(filtertypes);
//3. 获取所有源文件路径
ft.GetSubfiles(filepaths);
int filecount = filepaths.size();
if(filecount <= 0){
cout<<"no subfiles"<<endl;
return 0;
}
// 4.使用命令行参数指定的多线程数量
stringstream ss;
int threadnum = -1;
ss << argv[2];
ss >> threadnum;
if(threadnum <= 0 )
threadnum = 1;
int interval = (interval = filecount/threadnum)?interval:1;
thread_group grp;
list<SourceLine*> listsl;
/*
5. 每个线程处理span个源文件
*/
for(int i=0,j=0; i<threadnum && j<filecount; i++) {
int span = (i==(threadnum-1) && (filecount-j>interval))?(filecount-j):interval;
SourceLine *sl = new SourceLine(filepaths, j, j + span);
/*
此处可以通过sl->SetNoteString();设置编程语言的注释,默认是c++的注释
*/
j += span;
grp.add_thread(new boost::thread(boost::bind(&SourceLine::CalculateLine, sl)));
listsl.push_back(sl);
}
grp.join_all();
for(list<SourceLine*>::iterator listIter = listsl.begin(); listIter != listsl.end(); listIter++) {
if(*listIter != NULL) {
delete *listIter;
*listIter = NULL;
}
}
cout<<"empty lines:"<<SourceLine::GetEmptylines()<<endl
<<"note lines:"<<SourceLine::GetNotelines()<<endl
<<"code lines:"<<SourceLine::GetValidCodelines()<<endl
<<"total lines:"<<SourceLine::GetTotallines()<<endl;
char c;
cin>>c;
}
vs2010和g++编译通过。欢迎使用,发送bug.
转载于:https://blog.51cto.com/peacefulmind/1575857