mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
479 lines
10 KiB
C
479 lines
10 KiB
C
|
/*
|
||
|
* COPYRIGHT: See COPYING in the top level directory
|
||
|
* PROJECT: ReactOS project statistics
|
||
|
* FILE: stats.c
|
||
|
* PURPOSE: Main program file
|
||
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||
|
* REVISIONS:
|
||
|
* CSH 01/01-2002 Created
|
||
|
*/
|
||
|
#include <windows.h>
|
||
|
#include <tchar.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
typedef struct _EXTENSION_INFO
|
||
|
{
|
||
|
struct _EXTENSION_INFO * Next;
|
||
|
struct _FILE_INFO * StatInfoList;
|
||
|
TCHAR ExtName[16];
|
||
|
TCHAR ExpandedExtName[128];
|
||
|
DWORD nExtensions;
|
||
|
TCHAR Description[256];
|
||
|
DWORD FileCount;
|
||
|
DWORD LineCount;
|
||
|
DWORD EmptyLines;
|
||
|
} EXTENSION_INFO, *PEXTENSION_INFO;
|
||
|
|
||
|
typedef struct _FILE_INFO
|
||
|
{
|
||
|
struct _FILE_INFO * Next;
|
||
|
struct _FILE_INFO * StatInfoListNext;
|
||
|
PEXTENSION_INFO ExtInfo;
|
||
|
TCHAR FileName[MAX_PATH];
|
||
|
DWORD LineCount;
|
||
|
DWORD EmptyLines;
|
||
|
DWORD FunctionCount;
|
||
|
} FILE_INFO, *PFILE_INFO;
|
||
|
|
||
|
HANDLE FileHandle;
|
||
|
PEXTENSION_INFO ExtInfoList;
|
||
|
PFILE_INFO StatInfoList;
|
||
|
BOOLEAN SkipEmptyLines, BeSilent;
|
||
|
|
||
|
#define MAX_OPTIONS 2
|
||
|
TCHAR *Options[MAX_OPTIONS];
|
||
|
|
||
|
|
||
|
VOID
|
||
|
Initialize(VOID)
|
||
|
{
|
||
|
ExtInfoList = NULL;
|
||
|
StatInfoList = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
Cleanup(VOID)
|
||
|
{
|
||
|
PEXTENSION_INFO ExtInfo;
|
||
|
PEXTENSION_INFO NextExtInfo;
|
||
|
|
||
|
ExtInfo = ExtInfoList;
|
||
|
while (ExtInfo != NULL)
|
||
|
{
|
||
|
NextExtInfo = ExtInfo->Next;
|
||
|
HeapFree (GetProcessHeap(), 0, ExtInfo);
|
||
|
ExtInfo = NextExtInfo;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
PEXTENSION_INFO
|
||
|
AddExtension(LPTSTR ExtName,
|
||
|
LPTSTR Description)
|
||
|
{
|
||
|
PEXTENSION_INFO ExtInfo;
|
||
|
PEXTENSION_INFO Info;
|
||
|
TCHAR *t;
|
||
|
DWORD ln;
|
||
|
|
||
|
ExtInfo = (PEXTENSION_INFO) HeapAlloc (GetProcessHeap(), 0, sizeof (EXTENSION_INFO));
|
||
|
if (!ExtInfo)
|
||
|
return NULL;
|
||
|
|
||
|
for(t = ExtName; *t != _T('\0'); t += _tcslen(t) + 1);
|
||
|
ln = (DWORD)t - (DWORD)ExtName;
|
||
|
|
||
|
ZeroMemory (ExtInfo, sizeof (EXTENSION_INFO));
|
||
|
memcpy (ExtInfo->ExtName, ExtName, ln);
|
||
|
_tcscpy (ExtInfo->Description, Description);
|
||
|
|
||
|
for(t = ExtInfo->ExtName; *t != _T('\0'); t += _tcslen(t) + 1)
|
||
|
{
|
||
|
if(ExtInfo->nExtensions++ != 0)
|
||
|
_tcscat (ExtInfo->ExpandedExtName, _T(";"));
|
||
|
_tcscat (ExtInfo->ExpandedExtName, _T("*."));
|
||
|
_tcscat (ExtInfo->ExpandedExtName, t);
|
||
|
}
|
||
|
|
||
|
if (ExtInfoList)
|
||
|
{
|
||
|
Info = ExtInfoList;
|
||
|
while (Info->Next != NULL)
|
||
|
{
|
||
|
Info = Info->Next;
|
||
|
}
|
||
|
Info->Next = ExtInfo;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExtInfoList = ExtInfo;
|
||
|
}
|
||
|
|
||
|
return ExtInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
PFILE_INFO
|
||
|
AddFile(LPTSTR FileName,
|
||
|
PEXTENSION_INFO ExtInfo)
|
||
|
{
|
||
|
PFILE_INFO StatInfo;
|
||
|
PFILE_INFO Info;
|
||
|
|
||
|
StatInfo = (PFILE_INFO) HeapAlloc (GetProcessHeap(), 0, sizeof (FILE_INFO));
|
||
|
if (!StatInfo)
|
||
|
return NULL;
|
||
|
ZeroMemory (StatInfo, sizeof (FILE_INFO));
|
||
|
_tcscpy (StatInfo->FileName, FileName);
|
||
|
StatInfo->ExtInfo = ExtInfo;
|
||
|
|
||
|
if (ExtInfo->StatInfoList)
|
||
|
{
|
||
|
Info = ExtInfo->StatInfoList;
|
||
|
while (Info->StatInfoListNext != NULL)
|
||
|
{
|
||
|
Info = Info->StatInfoListNext;
|
||
|
}
|
||
|
Info->StatInfoListNext = StatInfo;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExtInfo->StatInfoList = StatInfo;
|
||
|
}
|
||
|
|
||
|
if (StatInfoList)
|
||
|
{
|
||
|
Info = StatInfoList;
|
||
|
while (Info->Next != NULL)
|
||
|
{
|
||
|
Info = Info->Next;
|
||
|
}
|
||
|
Info->Next = StatInfo;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StatInfoList = StatInfo;
|
||
|
}
|
||
|
|
||
|
return StatInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
CleanupAfterFile(VOID)
|
||
|
{
|
||
|
if(FileHandle != INVALID_HANDLE_VALUE)
|
||
|
CloseHandle (FileHandle);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
LoadFile(LPTSTR FileName)
|
||
|
{
|
||
|
LONG FileSize;
|
||
|
|
||
|
FileHandle = CreateFile (FileName, // Create this file
|
||
|
GENERIC_READ, // Open for reading
|
||
|
0, // No sharing
|
||
|
NULL, // No security
|
||
|
OPEN_EXISTING, // Open the file
|
||
|
FILE_ATTRIBUTE_NORMAL, // Normal file
|
||
|
NULL); // No attribute template
|
||
|
if (FileHandle == INVALID_HANDLE_VALUE)
|
||
|
return FALSE;
|
||
|
|
||
|
FileSize = GetFileSize (FileHandle, NULL);
|
||
|
if (FileSize <= 0)
|
||
|
{
|
||
|
CloseHandle (FileHandle);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ReadLines(PFILE_INFO StatInfo)
|
||
|
{
|
||
|
DWORD ReadBytes, LineLen;
|
||
|
static char FileBuffer[1024];
|
||
|
char LastChar = '\0';
|
||
|
char *Current;
|
||
|
|
||
|
LineLen = 0;
|
||
|
while(ReadFile (FileHandle, FileBuffer, sizeof(FileBuffer), &ReadBytes, NULL) && ReadBytes >= sizeof(char))
|
||
|
{
|
||
|
for(Current = FileBuffer; ReadBytes > 0; ReadBytes -= sizeof(char), Current++)
|
||
|
{
|
||
|
if(*Current == '\n' && LastChar == '\r')
|
||
|
{
|
||
|
LastChar = '\0';
|
||
|
if(!SkipEmptyLines || (LineLen > 0))
|
||
|
StatInfo->LineCount++;
|
||
|
if(LineLen == 0)
|
||
|
StatInfo->EmptyLines++;
|
||
|
LineLen = 0;
|
||
|
continue;
|
||
|
}
|
||
|
LastChar = *Current;
|
||
|
if(SkipEmptyLines && (*Current == ' ' || *Current == '\t'))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
if(*Current != '\r')
|
||
|
LineLen++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
StatInfo->LineCount += (LineLen > 0);
|
||
|
StatInfo->EmptyLines += ((LastChar != '\0') && (LineLen == 0));
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PrintStatistics(VOID)
|
||
|
{
|
||
|
PEXTENSION_INFO Info;
|
||
|
DWORD TotalFileCount;
|
||
|
DWORD TotalLineCount;
|
||
|
DWORD TotalAvgLF;
|
||
|
DWORD TotalEmptyLines;
|
||
|
|
||
|
TotalFileCount = 0;
|
||
|
TotalLineCount = 0;
|
||
|
TotalEmptyLines = 0;
|
||
|
Info = ExtInfoList;
|
||
|
|
||
|
for (Info = ExtInfoList; Info != NULL; Info = Info->Next)
|
||
|
{
|
||
|
TotalFileCount += Info->FileCount;
|
||
|
TotalLineCount += Info->LineCount;
|
||
|
TotalEmptyLines += Info->EmptyLines;
|
||
|
}
|
||
|
|
||
|
TotalAvgLF = (TotalFileCount ? TotalLineCount / TotalFileCount : 0);
|
||
|
|
||
|
for (Info = ExtInfoList; Info != NULL; Info = Info->Next)
|
||
|
{
|
||
|
DWORD AvgLF;
|
||
|
|
||
|
if (Info->FileCount != 0)
|
||
|
{
|
||
|
AvgLF = (Info->FileCount ? Info->LineCount / Info->FileCount : 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AvgLF = 0;
|
||
|
}
|
||
|
|
||
|
_tprintf (_T("\n"));
|
||
|
_tprintf (_T("File extension%c : %s\n"), ((Info->nExtensions > 1) ? _T('s') : _T(' ')), Info->ExpandedExtName);
|
||
|
_tprintf (_T("File ext. description : %s\n"), Info->Description);
|
||
|
_tprintf (_T("Number of files : %lu\n"), Info->FileCount);
|
||
|
_tprintf (_T("Number of lines : %lu\n"), Info->LineCount);
|
||
|
if(SkipEmptyLines)
|
||
|
_tprintf (_T("Number of empty lines : %lu\n"), Info->EmptyLines);
|
||
|
_tprintf (_T("Proportion of lines : %.2f %%\n"), (float)(TotalLineCount ? (((float)Info->LineCount * 100) / (float)TotalLineCount) : 0));
|
||
|
_tprintf (_T("Average no. lines/file : %lu\n"), AvgLF);
|
||
|
}
|
||
|
|
||
|
_tprintf (_T("\n"));
|
||
|
_tprintf (_T("Total number of files : %lu\n"), TotalFileCount);
|
||
|
_tprintf (_T("Total number of lines : %lu\n"), TotalLineCount);
|
||
|
if(SkipEmptyLines)
|
||
|
_tprintf (_T("Total number of empty lines : %lu\n"), TotalEmptyLines);
|
||
|
_tprintf (_T("Average no. lines/file : %lu\n"), TotalAvgLF);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ProcessFiles(LPTSTR Path)
|
||
|
{
|
||
|
WIN32_FIND_DATA FindFile;
|
||
|
PEXTENSION_INFO Info;
|
||
|
TCHAR SearchPath[256];
|
||
|
TCHAR FileName[256];
|
||
|
TCHAR *Ext;
|
||
|
HANDLE SearchHandle;
|
||
|
BOOL More;
|
||
|
|
||
|
Info = ExtInfoList;
|
||
|
while (Info != NULL)
|
||
|
{
|
||
|
Ext = Info->ExtName;
|
||
|
do
|
||
|
{
|
||
|
ZeroMemory (&FindFile, sizeof (FindFile));
|
||
|
_tcscpy (SearchPath, Path);
|
||
|
_tcscat (SearchPath, _T("\\*."));
|
||
|
_tcscat (SearchPath, Ext);
|
||
|
_tcscpy (FindFile.cFileName, SearchPath);
|
||
|
SearchHandle = FindFirstFile (SearchPath, &FindFile);
|
||
|
if (SearchHandle != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
More = TRUE;
|
||
|
while (More)
|
||
|
{
|
||
|
if (!(FindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||
|
{
|
||
|
_tcscpy (FileName, Path);
|
||
|
_tcscat (FileName, _T("\\"));
|
||
|
_tcscat (FileName, FindFile.cFileName);
|
||
|
|
||
|
if (LoadFile (FileName))
|
||
|
{
|
||
|
PFILE_INFO StatInfo;
|
||
|
|
||
|
StatInfo = AddFile (FindFile.cFileName, Info);
|
||
|
if (!StatInfo)
|
||
|
{
|
||
|
_tprintf (_T("Not enough free memory.\n"));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ReadLines (StatInfo);
|
||
|
|
||
|
Info->FileCount++;
|
||
|
Info->LineCount += StatInfo->LineCount;
|
||
|
Info->EmptyLines += StatInfo->EmptyLines;
|
||
|
|
||
|
CleanupAfterFile();
|
||
|
}
|
||
|
}
|
||
|
More = FindNextFile (SearchHandle, &FindFile);
|
||
|
}
|
||
|
FindClose (SearchHandle);
|
||
|
}
|
||
|
Ext += _tcslen(Ext) + 1;
|
||
|
} while(*Ext != _T('\0'));
|
||
|
Info = Info->Next;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ProcessDirectories(LPTSTR Path)
|
||
|
{
|
||
|
WIN32_FIND_DATA FindFile;
|
||
|
TCHAR SearchPath[MAX_PATH];
|
||
|
HANDLE SearchHandle;
|
||
|
BOOL More;
|
||
|
|
||
|
if(!BeSilent)
|
||
|
{
|
||
|
_tprintf (_T("Processing %s ...\n"), Path);
|
||
|
}
|
||
|
|
||
|
_tcscpy (SearchPath, Path);
|
||
|
_tcscat (SearchPath, _T("\\*.*"));
|
||
|
|
||
|
SearchHandle = FindFirstFileEx (SearchPath,
|
||
|
FindExInfoStandard,
|
||
|
&FindFile,
|
||
|
FindExSearchLimitToDirectories,
|
||
|
NULL,
|
||
|
0);
|
||
|
if (SearchHandle != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
More = TRUE;
|
||
|
while (More)
|
||
|
{
|
||
|
if ((FindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||
|
&& (_tcscmp (FindFile.cFileName, _T(".")) != 0)
|
||
|
&& (_tcscmp (FindFile.cFileName, _T("..")) != 0)
|
||
|
&& (_tcscmp (FindFile.cFileName, _T("CVS")) != 0)
|
||
|
&& (_tcscmp (FindFile.cFileName, _T(".svn")) != 0))
|
||
|
{
|
||
|
_tcscpy (SearchPath, Path);
|
||
|
_tcscat (SearchPath, _T("\\"));
|
||
|
_tcscat (SearchPath, FindFile.cFileName);
|
||
|
if (!ProcessDirectories (SearchPath))
|
||
|
return FALSE;
|
||
|
if (!ProcessFiles (SearchPath))
|
||
|
return FALSE;
|
||
|
}
|
||
|
More = FindNextFile (SearchHandle, &FindFile);
|
||
|
}
|
||
|
FindClose (SearchHandle);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
Execute(LPTSTR Path)
|
||
|
{
|
||
|
if (!ExtInfoList)
|
||
|
{
|
||
|
_tprintf (_T("No extensions specified.\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!ProcessDirectories (Path))
|
||
|
{
|
||
|
_tprintf (_T("Failed to process directories.\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!ProcessFiles (Path))
|
||
|
{
|
||
|
_tprintf (_T("Failed to process files.\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PrintStatistics();
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
IsOptionSet(TCHAR *Option)
|
||
|
{
|
||
|
int i;
|
||
|
for(i = 0; i < MAX_OPTIONS; i++)
|
||
|
{
|
||
|
if(!Options[i])
|
||
|
continue;
|
||
|
|
||
|
if(!_tcscmp(Options[i], Option))
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
int _tmain(int argc, _TCHAR * argv[])
|
||
|
{
|
||
|
int a;
|
||
|
|
||
|
_tprintf (_T("ReactOS Project Statistics\n"));
|
||
|
_tprintf (_T("==========================\n\n"));
|
||
|
|
||
|
if (argc < 2 || argc > 2 + MAX_OPTIONS)
|
||
|
{
|
||
|
_tprintf(_T("Usage: stats [-e] [-s] directory\n"));
|
||
|
_tprintf(_T(" -e: don't count empty lines\n"));
|
||
|
_tprintf(_T(" -s: be silent, don't print directories while processing\n"));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
Initialize();
|
||
|
AddExtension (_T("c\0\0"), _T("Ansi C Source files"));
|
||
|
AddExtension (_T("cpp\0cxx\0\0"), _T("C++ Source files"));
|
||
|
AddExtension (_T("h\0\0"), _T("Header files"));
|
||
|
|
||
|
for(a = 1; a < argc - 1; a++)
|
||
|
{
|
||
|
Options[a - 1] = argv[a];
|
||
|
}
|
||
|
|
||
|
SkipEmptyLines = IsOptionSet(_T("-e"));
|
||
|
BeSilent = IsOptionSet(_T("-s"));
|
||
|
|
||
|
Execute (argv[argc - 1]);
|
||
|
Cleanup();
|
||
|
|
||
|
return 0;
|
||
|
}
|