最近在找工作,某公司出了这么个题:统计项目源代码行数。
为了实现跨平台用了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.
时间: 2024-10-25 20:21:39