Utility to Product Source Code Statistics
Posted
by Valery R. Kim
on January 26th, 2000
This utility is for developers that need to obtain statistics concerning their source code. It will scan a directory structure and obtain all available statistics information from the source code such as total code lines, comments lines, headers lines, code and resources lines. Scanning can be recursive and countable files extensions can de defined.
// Copyright by Valery R. Kim, 20.01.2000. Freeware. #include#include #include #include // White space delimiters #define STR_WHITE_SPACE "/r/n /t,;" // Structure accumulating statistics information typedef struct _SCAN_INFO { unsigned long lHeaders; unsigned long lCode; unsigned long lResources; unsigned long lLines; unsigned long lComments; _SCAN_INFO() { lLines=lComments=lResources=lCode=lHeaders=0; } _SCAN_INFO& operator+(_SCAN_INFO& ScanInfo) { lLines+=ScanInfo.lLines; lComments+=ScanInfo.lComments; lHeaders+=ScanInfo.lHeaders; lCode+=ScanInfo.lCode; lResources+=ScanInfo.lResources; return *this; } _SCAN_INFO& operator+=(_SCAN_INFO& ScanInfo) { lLines+=ScanInfo.lLines; lComments+=ScanInfo.lComments; lHeaders+=ScanInfo.lHeaders; lCode+=ScanInfo.lCode; lResources+=ScanInfo.lResources; return *this; } } SCAN_INFO, *PSCAN_INFO; // Default predefined countable extensions static const char pPredefinedExts[]={"c cpp h hpp rc"}; // Function filling template vector by countable //files extensions template void FillExts(CArray & pDest, char** pExts) { char* pItem=NULL; int i=0; while(pItem=pExts[i]){ pDest.Add(T(pExts[i])); i++; } } // Function filling template array from by default countable extensions template void FillExts(CArray & pDest, const char pSrc[]) { char szBuf[_MAX_PATH]; strcpy(szBuf, pSrc); // Looking for substrings devided by white space char* pItem=strtok(szBuf, STR_WHITE_SPACE); while(pItem){ pDest.Add(T(pItem)); pItem=strtok(NULL, STR_WHITE_SPACE); } } // Function scanning file for statistics information void ScanFile(CString sFileName, PSCAN_INFO pScanInfo, unsigned long* plType) { FILE *f=fopen(sFileName, "r"); if(!f) return; char szBuf[4096]; // Loop for file text lines while(fgets(szBuf, sizeof(szBuf), f)){ pScanInfo->lLines++; (*plType)++; // Trim left leading white spaces CString s(szBuf); s.TrimLeft(); if(s.Left(2)=="//") pScanInfo->lComments++; } fclose(f); } // Recursive function looping by subfolders template void FoldersLoop(CString sDir, CArray & pExts, bool bRecursive, SCAN_INFO& FolderScanInfo) { // Don't make statistics for folders "." and ".." if(sDir[sDir.GetLength()-1]=='.') return; WIN32_FIND_DATA findData; HANDLE hFind=FindFirstFile(sDir+"//*.*", &findData); if(hFind==INVALID_HANDLE_VALUE){ // No files in this folder return; } CArray pFiles; CArray pTypes; do{ if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && bRecursive){ // Scan this folder FoldersLoop(sDir+"//"+findData.cFileName, pExts, bRecursive, FolderScanInfo); } else { // Get file extension CString sFileName(findData.cFileName); CString sExt=sFileName.Right(sFileName.GetLength() -sFileName.Find(".")-1); if(sExt!=""){ sExt.MakeLower(); // Look if this extension is countable for(int i=0; i // File satisfies conditions for extension pFiles.Add(sDir+"//"+findData.cFileName); // 0-length offset from structure addr if(sExt=="hpp" || sExt=="h") pTypes.Add(0); // 1-length offset from structure addr else if(sExt=="cpp" || sExt=="c") pTypes.Add(1); // 2-length offset from structure addr else if(sExt=="rc") pTypes.Add(2); } } } } while(FindNextFile(hFind, &findData)); cout << sDir; // If we've found anything if(pFiles.GetSize()){ cout << endl; for(int i=0; i // Scan this file according to it's type ScanFile(pFiles[i], &ScanInfo, &(ScanInfo.lHeaders)+pTypes[i]); FolderScanInfo+=ScanInfo; cout << "."; } } cout << endl; // Free templates data memory pFiles.RemoveAll(); pTypes.RemoveAll(); } // Main entry point int main(int argc, char* argv[]) { // Check parameters list if(argc<=1){ cout << "Bad arguments list. Format is as follows:" << endl << "StatCode.exe <dir_name> [-R] [exts]" << endl << " key R - means recursive statistics" << endl << " exts - list of countable files extensions divided by " "white spaces." << endl << " By default *.cpp, *.c, *.h, *.cpp, *.rc files are " "counted." << endl; return 0; } // Base directory CString sBaseDir(argv[1]); // Recursive flag CString s(argv[2]); s.MakeUpper(); bool bRecursive=(s=="-R"); // Extensions int nExtStart=2; if(bRecursive) nExtStart++; // Extensions buffer CArray pExts; if(nExtStart>=argc){ // Fill extensions buffer with predefined extensions FillExts(pExts, pPredefinedExts); } else { // Get extensions from command line FillExts(pExts, argv+nExtStart); } SCAN_INFO ScanInfo; // Start loop for folders from base dir FoldersLoop(sBaseDir, pExts, bRecursive, ScanInfo); pExts.RemoveAll(); // Ouput all statistics accumulated cout << endl << "Total lines : " << ScanInfo.lLines << endl << "Comments : " << ScanInfo.lComments << " (" << (int)(100.0*ScanInfo.lComments/ScanInfo.lLines) << "%)" << endl << "Headers : " << ScanInfo.lHeaders << " (" << (int)(100.0*ScanInfo.lHeaders/ScanInfo.lLines) << "%)" << endl << "Code : " << ScanInfo.lCode << " (" << (int)(100.0*ScanInfo.lCode/ScanInfo.lLines) << "%)" << endl << "Resources : " << ScanInfo.lResources << " (" << (int)(100.0*ScanInfo.lResources/ScanInfo.lLines) << "%)" << endl; return 0; }

Comments
Compiler Bugs???
Posted by fsergiu on 02/26/2006 01:52pmRE: Way to go!
Posted by Legacy on 08/01/2000 12:00amOriginally posted by: slonmron
I wonder why compilers don't do this.
Actually they really know what the statistics are and it's
easy to implement right there, because they parse all the code.
Vary useful article!
ReplyWhat about old-fashion comments ? (/* this is also a comment */)
Posted by Legacy on 01/27/2000 12:00amOriginally posted by: Ga�tan Frenoy
Very disappointed by my poor score (10% of comments on 150,000 lines), I've searched the reason and I've found
that the /* old-fashioned comments */ are not counted :(
And also, the ending line comments are not added to the lComments counter :(
Anyway, this tool is cool and very easy to use and modify.
Reply