Utility to Product Source Code Statistics

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;
}

Downloads

Download source - 3 Kb


Comments

  • Compiler Bugs???

    Posted by fsergiu on 02/26/2006 01:52pm

    I got the following linker errors:
    nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
    nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
    Debug/Test.exe : fatal error LNK1120: 2 unresolved externals
    Error executing link.exe.
    Why? What is werong?
    Thanks, Sergiu

    Reply
  • RE: Way to go!

    Posted by Legacy on 08/01/2000 12:00am

    Originally 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!

    Reply
  • What about old-fashion comments ? (/* this is also a comment */)

    Posted by Legacy on 01/27/2000 12:00am

    Originally 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
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds