代码统计工具1.1版本技术文档
代碼統計工具1.1版本技術文檔
?
說明:主要記錄自己在做這個項目的過程中用到的方法和相關技術
?
1.首先面臨的問題就是怎樣選擇一個目錄,網上搜索了一下,下面是解決方案(用到目錄對話框)
(1)從默認的磁盤總目錄下開始選擇:
TCHAR?szPath[MAX_PATH];
BROWSEINFO?br;
ITEMIDLIST*?pItem;
?
br.hwndOwner?=?this->GetSafeHwnd();
br.pidlRoot?=?0;
br.pszDisplayName?=?0;
br.lpszTitle?=?"選擇路徑";
br.ulFlags?=?BIF_STATUSTEXT;
br.lpfn?=?0;
br.iImage?=?0;
br.lParam?=?0;
?
pItem?=?SHBrowseForFolder(&br);
if(pItem?!=?NULL)
{
if(SHGetPathFromIDList(pItem,szPath)?==?TRUE)
{
//這就是我們得到的目錄名稱
CString?strDir?=?szPath;
}
}
(2)自己設定需要目錄對話框默認選擇的目錄
第一步:(和第一種不同的是需要為這個目錄對話框設定自定義回調函數)
TCHAR?szDefaultDir[MAX_PATH];
CString?strDef(_T("d://C++//"));//需要設定的默認的目錄
memcpy(szDefaultDir,?strDef.GetBuffer(strDef.GetLength()),?strDef.GetLength());
strDef.ReleaseBuffer();
?
TCHAR?szPath[MAX_PATH];
BROWSEINFO?br;
ITEMIDLIST*?pItem;
?
br.hwndOwner?=?this->GetSafeHwnd();
br.pidlRoot?=?0;
br.pszDisplayName?=?0;
br.lpszTitle?=?"選擇路徑";
br.ulFlags?=?BIF_STATUSTEXT;
//設置CALLBACK函數
br.lpfn?=?FA_BrowseCallbackProc?;???????
br.iImage?=?0;
//設置默認路徑
br.lParam?=?long(&szDefaultDir);????
/*說明:?在Unicode環境下,編譯測試,此處的默認路徑無法起作用
/*???????需要手動轉換成TChar/WChar
/*???????TChar?strBuffer[MAX_PATH];
/*???????wcscpy(strBuffer,?szDefaultDir);*/
?
pItem?=?SHBrowseForFolder(&br);
if?(pItem?!=?NULL)
{
if?(SHGetPathFromIDList(pItem,szPath)?==?TRUE)
{
//這就是我們得到的目錄名稱
m_strDirPath?=?szPath;
}
}
第二步:設計回調函數
int?CALLBACK?FA_BrowseCallbackProc(HWND?hwnd,?UINT?uMsg,?LPARAM?lParam,?LPARAM?lpData)
{
switch(uMsg)
{
case?BFFM_INITIALIZED:????//初始化消息
//傳遞默認打開路徑?(方法一)
//::SendMessage(hwnd,?BFFM_SETSELECTION,TRUE,(LPARAM)"C://Program?Files");?
?? ?//傳遞默認打開路徑?(方法二,前提是lpData提前設置好)
::SendMessage(hwnd,?BFFM_SETSELECTION,?TRUE,?lpData);???????
break;
case?BFFM_SELCHANGED:????//選擇路徑變化,
{
char?curr[MAX_PATH];???
SHGetPathFromIDList((LPCITEMIDLIST)lParam,curr);???
::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)curr);???
}
break;
default:
break;
}
?
return?0;???
}
(3)用到的數據結構(MSDN查看相應介紹):
typedef?struct?_browseinfo?{?
????HWND?hwndOwner;?
????LPCITEMIDLIST?pidlRoot;?
????LPTSTR?pszDisplayName;?
????LPCTSTR?lpszTitle;?
????UINT?ulFlags;?
????BFFCALLBACK?lpfn;?
????LPARAM?lParam;?
????int?iImage;?
}?BROWSEINFO,?*PBROWSEINFO,?*LPBROWSEINFO;?
?
typedef?struct?_ITEMIDLIST?{?
SHITEMID?mkid;
}?ITEMIDLIST,?*?LPITEMIDLIST;?
typedef?const?ITEMIDLIST?*?LPCITEMIDLIST;
?
2.遍歷一個目錄(需要遞歸遍歷下面所有的文件)并保存源代碼文件的文件名(后綴名為.c,?cpp,?.h,.?java)
/********************************************************************
*?函數名:
FA_ReadDirectory(CString?strDirPath)
*?函數功能:
讀取一個目錄下的所有文件
*?輸入參數:?
strDirPath:目錄的完整路徑
*?輸出參數:?
*?返回值:?
*?用到的全局變量和結構:?
*?其他說明:
********************************************************************/
void?CFA_CodeAnalysisView::FA_ReadDirectory(CString?strDirPath)
{
WIN32_FIND_DATA?tFind?=?{0};
CString?strTemp;
CString?strDirTemp;
CString?strSuffix;
?
strDirPath.Format("%s//*",?strDirPath);
HANDLE?hSearch?=?::FindFirstFile(strDirPath,?&tFind);???
if?(hSearch?==?INVALID_HANDLE_VALUE)???
{???
return?;???
}???
//過濾掉.和..文件目錄
::FindNextFile(hSearch,?&tFind);
while?(::FindNextFile(hSearch,?&tFind))
{
? strDirTemp?=?strDirPath;
strTemp.Format("%s",?tFind.cFileName);
//去掉最后那一個*通配符
strDirTemp?=?strDirTemp.Left(strDirTemp.GetLength()-1);
strDirTemp?+=?strTemp;
?
if?((tFind.dwFileAttributes?&?FILE_ATTRIBUTE_DIRECTORY)?!=?0)
{
FA_ReadDirectory(strDirTemp);
}?
?
strSuffix?=?strTemp.Right(strTemp.GetLength()?-?strTemp.Find('.'));
if?(!strSuffix.CompareNoCase(".h")?||?!strSuffix.CompareNoCase(".cpp")?||
!strSuffix.CompareNoCase(".c")?||?!strSuffix.CompareNoCase(".java"))
{
m_strFileName[m_iFileCount]?=?strDirTemp;
m_iFileCount++;
}
}
::FindClose(hSearch);?
}
知識點:?FindFirstFile?和?FindNextFile?函數以及下面這個結構體.
typedef?struct?_WIN32_FIND_DATA?{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwOID;
TCHAR cFileName[MAX_PATH];
}?WIN32_FIND_DATA;
?
3.計算
/********************************************************************
*?函數名:
FA_CalculateLines()
*?函數功能:
計算各個文件的代碼行數,注釋函數以及空白函數
*?輸入參數:?
*?輸出參數:?
*?返回值:?
*?用到的全局變量和結構:?
*?其他說明:
********************************************************************/
void?CFA_CodeAnalysisView::FA_CalculateLines()
{
m_lBlankTotalLines?=?0;
m_lNoteTotalLines?=?0;
m_lCodeTotalLines?=?0;
?
CString?strFileName;
CString?strRecvData;
CStdioFile?file;
BOOL?bNoteEnd?=?FALSE;
int?blankLines?=?0;
int?noteLines?=?0;
int?codeLines?=?0;
int?blankTotalLines?=?0;
int?noteTotalLines?=?0;
int?codeTotalLines?=?0;
?
CRect?rt;
GetClientRect(rt);
int?iAverHigh?=?rt.Height()?/?32;
?
/************************************************************************/
/*?以下代碼段計算每個文件的有效代碼行數,注釋行數以及空行數
/*計算所有文件的總的相對應的行數
/*用的是一個從CFile繼承的類CStdioFile,因為它有一個方法可以直接讀一行文件
/*內容到一個CString中
/************************************************************************/
??? for?(int?i=0;?i<m_iFileCount;?i++)
{
strFileName?=?m_strFileName[i];
?
//以只讀模式打開文件
file.Open(strFileName,?CFile::modeRead);
//讀入一行帶字符串中
while?(file.ReadString(strRecvData))
{
//判斷是否是多行注釋的開頭
if?(!strRecvData.Left(2).Compare("/*")?&&?!bNoteEnd)
{
//判斷多行注釋是否在當前行的結束
if?(strRecvData.Right(2).Compare("*/"))
{
bNoteEnd?=?TRUE;
}
noteLines++;
}
//判斷是不是多行注釋的結束
else?if?(!strRecvData.Right(2).Compare("*/")?&&?bNoteEnd)
{
noteLines++;
bNoteEnd?=?FALSE;
}
//判斷當前行在多行注釋中間部分
else?if?(bNoteEnd)
{
noteLines++;
}
//判斷是否是空行
else?if?(strRecvData.TrimLeft("/t?"),?strRecvData.IsEmpty())
{
blankLines++;
}
//判斷是否是單行注釋
else?if?(!strRecvData.Left(2).Compare("//"))
{
noteLines++;
}
//否則是有效代碼行
else
{
codeLines++;
}
}
//注意用完一個文件后關閉
file.Close();
m_iBlankLines[i]?=?blankLines;
m_iNoteLines[i]?=?noteLines;
m_iCodeLines[i]?=?codeLines;
m_lBlankTotalLines?+=?blankLines;
m_lNoteTotalLines?+=?noteLines;
m_lCodeTotalLines?+=?codeLines;
blankLines?=?0;
noteLines?=?0;
codeLines?=?0;
}
//根據計算結果計算視圖總共的高度
if?(m_iFileCount?>?7)
{
CSize?sizeTotal;
sizeTotal.cx?=?600;
sizeTotal.cy?=?m_iFileCount?*?iAverHigh?*?4;
SetScrollSizes(MM_TEXT,?sizeTotal);
}
}
知識點:CStdioFile類的使用以及它的函數ReadStirng讀入文件的一行到一個字符串
?
4.輸出計算結果:
/********************************************************************
*?函數名:
DrawFileText(CDC?*pDC)
*?函數功能:
輸出文件名,及各個計算結果
*?輸入參數:?
pDC:用于輸出文字的CDC指針
*?輸出參數:?
*?返回值:?
*?用到的全局變量和結構:?
*?其他說明:
********************************************************************/
void?CFA_CodeAnalysisView::FA_DrawFileText(CDC?*pDC)
{
CString?strFileName;
?
pDC->SetBkMode(TRANSPARENT);
CRect?rt;
GetClientRect(rt);
int?iAverHigh?=?rt.Height()?/?32;
?
pDC->SetTextColor(RGB(0,?0,?0));
strFileName.Format("此目錄下各個行數的總數如下(總共有%d個文件):",?m_iFileCount);
pDC->DrawText(strFileName,?CRect(0,?0,?rt.Width(),??20),?DT_LEFT);
pDC->SetTextColor(RGB(255,?0,?0));
strFileName.Format("總代碼有?%d?行",?m_lCodeTotalLines);
pDC->DrawText(strFileName,?CRect(50,?1?*?iAverHigh,?rt.Width(),?1?*?iAverHigh?+?20),?DT_LEFT);
pDC->SetTextColor(RGB(0,?255,?0));
strFileName.Format("總注釋有?%d?行",?m_lNoteTotalLines);
pDC->DrawText(strFileName,?CRect(50,?2?*?iAverHigh,?rt.Width(),?2?*?iAverHigh?+?20),?DT_LEFT);
pDC->SetTextColor(RGB(0,?0,?255));
strFileName.Format("總空行有?%d?行",?m_lBlankTotalLines);
pDC->DrawText(strFileName,?CRect(50,?3?*?iAverHigh,?rt.Width(),?3?*?iAverHigh?+?20),?DT_LEFT);
?
??? for?(int?i=0;?i<m_iFileCount;?i++)
{
strFileName?=?m_strFileName[i];
pDC->SetTextColor(RGB(0,?0,?0));
pDC->DrawText(strFileName.Right(strFileName.GetLength()?-?m_strDirPath.GetLength()?-1),
CRect(0,?(i+1)?*?4?*?iAverHigh,?rt.Width(),?(i+1)?*?4?*?iAverHigh?+?20),?DT_LEFT);
pDC->SetTextColor(RGB(255,?0,?0));
strFileName.Format("代碼有?%d?行",?m_iCodeLines[i]);
pDC->DrawText(strFileName,?CRect(50,?((i+1)?*?4?+?1)?*?iAverHigh,?rt.Width(),
((i+1)?*?4?+?1)*?iAverHigh?+?20),?DT_LEFT);
pDC->SetTextColor(RGB(0,?255,?0));
strFileName.Format("注釋有?%d?行",?m_iNoteLines[i]);
pDC->DrawText(strFileName,?CRect(50,?((i+1)?*?4?+?2)?*?iAverHigh,?rt.Width(),
((i+1)?*?4?+?2)*?iAverHigh?+?20),?DT_LEFT);
pDC->SetTextColor(RGB(0,?0,?255));
strFileName.Format("空行有?%d?行",?m_iBlankLines[i]);
pDC->DrawText(strFileName,?CRect(50,?((i+1)?*?4?+?3)?*?iAverHigh,?rt.Width(),
((i+1)?*?4?+?3)*?iAverHigh?+?20),?DT_LEFT);
}
}
5.運行效果
6.總結
此項目雖然很小,但是比較實用,我們可以簡單的計算一個目錄下或是一個工程有多少代碼行,注釋行以及空白行。對于自己編程多少的檢驗,以及一個團隊內每個成員的編程多少做統計。
?
轉載于:https://www.cnblogs.com/brucewoo/archive/2010/07/08/2252036.html
總結
以上是生活随笔為你收集整理的代码统计工具1.1版本技术文档的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IPv6套接字编程介绍
- 下一篇: 无聊,写写工作日记吧.