45669648d2c9eda50621fc329970fd3a59a4d295
[reactos.git] / apps / utils / stats / stats.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS project statistics
4  * FILE:        stats.c
5  * PURPOSE:     Main program file
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/01-2002 Created
9  */
10 #include <windows.h>
11 #include <tchar.h>
12
13
14 typedef struct _EXTENSION_INFO
15 {
16   struct _EXTENSION_INFO * Next;
17   struct _FILE_INFO * StatInfoList;
18   TCHAR ExtName[16];
19   TCHAR Description[256];
20   DWORD FileCount;
21   DWORD LineCount;
22 } EXTENSION_INFO, *PEXTENSION_INFO;
23
24 typedef struct _FILE_INFO
25 {
26   struct _FILE_INFO * Next;
27   struct _FILE_INFO * StatInfoListNext;
28   PEXTENSION_INFO ExtInfo;
29   TCHAR FileName[256];
30   DWORD LineCount;
31   DWORD FunctionCount;
32 } FILE_INFO, *PFILE_INFO;
33
34
35 DWORD TotalLineCount;
36 PCHAR FileBuffer;
37 DWORD FileBufferSize;
38 CHAR Line[256];
39 DWORD CurrentOffset;
40 DWORD CurrentChar;
41 DWORD CurrentLine;
42 DWORD LineLength;
43 PEXTENSION_INFO ExtInfoList;
44 PFILE_INFO StatInfoList;
45
46
47 VOID
48 Initialize()
49 {
50   TotalLineCount = 0;
51   FileBuffer = NULL;
52   FileBufferSize = 0;
53   CurrentOffset = 0;
54   CurrentLine = 0;
55   LineLength = 0;
56   ExtInfoList = NULL;
57   StatInfoList = NULL;
58 }
59
60
61 VOID
62 Cleanup()
63 {
64   PEXTENSION_INFO ExtInfo;
65   PEXTENSION_INFO NextExtInfo;
66
67   ExtInfo = ExtInfoList;
68   while (ExtInfo != NULL)
69   {
70     NextExtInfo = ExtInfo->Next;
71     HeapFree (GetProcessHeap(), 0, ExtInfo);
72     ExtInfo = NextExtInfo;
73   }
74 }
75
76
77 PEXTENSION_INFO
78 AddExtension(LPTSTR ExtName,
79   LPTSTR Description)
80 {
81   PEXTENSION_INFO ExtInfo;
82   PEXTENSION_INFO Info;
83
84   ExtInfo = (PEXTENSION_INFO) HeapAlloc (GetProcessHeap(), 0, sizeof (EXTENSION_INFO));
85   if (!ExtInfo)
86     return NULL;
87   ZeroMemory (ExtInfo, sizeof (EXTENSION_INFO));
88   _tcscpy (ExtInfo->ExtName, ExtName);
89   _tcscpy (ExtInfo->Description, Description);
90
91   if (ExtInfoList)
92   {
93     Info = ExtInfoList;
94     while (Info->Next != NULL)
95     {
96       Info = Info->Next;
97     }
98     Info->Next = ExtInfo;
99   }
100   else
101   {
102     ExtInfoList = ExtInfo;
103   }
104
105   return ExtInfo;
106 }
107
108
109 PFILE_INFO
110 AddFile(LPTSTR FileName,
111   PEXTENSION_INFO ExtInfo)
112 {
113   PFILE_INFO StatInfo;
114   PFILE_INFO Info;
115
116   StatInfo = (PFILE_INFO) HeapAlloc (GetProcessHeap(), 0, sizeof (FILE_INFO));
117   if (!StatInfo)
118     return NULL;
119   ZeroMemory (StatInfo, sizeof (FILE_INFO));
120   _tcscpy (StatInfo->FileName, FileName);
121   StatInfo->ExtInfo = ExtInfo;
122
123   if (ExtInfo->StatInfoList)
124   {
125     Info = ExtInfo->StatInfoList;
126     while (Info->StatInfoListNext != NULL)
127     {
128       Info = Info->StatInfoListNext;
129     }
130     Info->StatInfoListNext = StatInfo;
131   }
132   else
133   {
134     ExtInfo->StatInfoList = StatInfo;
135   }
136
137   if (StatInfoList)
138   {
139     Info = StatInfoList;
140     while (Info->Next != NULL)
141     {
142       Info = Info->Next;
143     }
144     Info->Next = StatInfo;
145   }
146   else
147   {
148     StatInfoList = StatInfo;
149   }
150
151   return StatInfo;
152 }
153
154
155 VOID
156 CleanupAfterFile()
157 {
158   if (FileBuffer)
159   {
160     HeapFree (GetProcessHeap(), 0, FileBuffer);
161     FileBuffer = NULL;
162   }
163 }
164
165
166 BOOL
167 LoadFile(LPTSTR FileName)
168 {
169   HANDLE FileHandle;
170   DWORD BytesRead;
171   LONG FileSize;
172
173   FileHandle = CreateFile (FileName, // Create this file
174     GENERIC_READ,                    // Open for reading
175     0,                               // No sharing
176     NULL,                            // No security
177     OPEN_EXISTING,                   // Open the file
178     FILE_ATTRIBUTE_NORMAL,           // Normal file
179     NULL);                           // No attribute template
180   if (FileHandle == INVALID_HANDLE_VALUE)
181     return FALSE;
182
183   FileSize = GetFileSize (FileHandle, NULL);
184   if (FileSize < 0)
185   {
186     CloseHandle (FileHandle);
187     return FALSE;
188   }
189
190   FileBufferSize = (DWORD) FileSize;
191
192   FileBuffer = (PCHAR) HeapAlloc (GetProcessHeap(), 0, FileBufferSize);
193   if (!FileBuffer)
194   {
195     CloseHandle (FileHandle);
196     return FALSE;
197   }
198
199   if (!ReadFile (FileHandle, FileBuffer, FileBufferSize, &BytesRead, NULL))
200   {
201     CloseHandle(FileHandle);
202     HeapFree (GetProcessHeap(), 0, FileBuffer);
203     FileBuffer = NULL;
204     return FALSE;
205   }
206
207   CloseHandle (FileHandle);
208
209   CurrentOffset = 0;
210   CurrentLine = 0;
211   CurrentChar = 0;
212
213   return TRUE;
214 }
215
216
217 BOOL
218 ReadLine()
219 /*
220  * FUNCTION: Reads the next line into the line buffer
221  * RETURNS:
222  *     TRUE if there is a new line, FALSE if not
223  */
224 {
225   ULONG i, j;
226   TCHAR ch;
227
228   if (CurrentOffset >= FileBufferSize)
229     return FALSE;
230
231   i = 0;
232   while (((j = CurrentOffset + i) < FileBufferSize) && (i < sizeof (Line)) &&
233     ((ch = FileBuffer[j]) != 0x0D))
234   {
235     Line[i] = ch;
236     i++;
237   }
238
239   Line[i]    = '\0';
240   LineLength = i;
241   
242   if (FileBuffer[CurrentOffset + i + 1] == 0x0A)
243     CurrentOffset++;
244
245   CurrentOffset += i + 1;
246
247   CurrentChar = 0;
248
249   CurrentLine++;
250
251   return TRUE;
252 }
253
254
255 VOID
256 DoStatisticsForFile(PFILE_INFO StatInfo)
257 {
258   while (ReadLine())
259   {
260   }
261   StatInfo->LineCount = CurrentLine;
262 }
263
264
265 VOID
266 PrintStatistics()
267 {
268   PEXTENSION_INFO Info;
269   DWORD TotalFileCount;
270   DWORD TotalLineCount;
271   DWORD TotalAvgLF;
272
273   TotalFileCount = 0;
274   TotalLineCount = 0;
275   Info = ExtInfoList;
276
277   while (Info != NULL)
278   {
279     DWORD AvgLF;
280
281     if (Info->FileCount != 0)
282     {
283       AvgLF = Info->LineCount / Info->FileCount;
284     }
285     else
286     {
287       AvgLF = 0;
288     }
289
290     _tprintf (_T("\n"));
291     _tprintf (_T("File extension         : %s\n"), Info->ExtName);
292     _tprintf (_T("File ext. description  : %s\n"), Info->Description);
293     _tprintf (_T("Number of files        : %d\n"), Info->FileCount);
294     _tprintf (_T("Number of lines        : %d\n"), Info->LineCount);
295     _tprintf (_T("Average no. lines/file : %d\n"), AvgLF);
296
297     TotalFileCount += Info->FileCount;
298     TotalLineCount += Info->LineCount;
299
300     Info = Info->Next;
301   }
302
303   TotalAvgLF = TotalLineCount / TotalFileCount;
304
305   _tprintf (_T("\n"));
306   _tprintf (_T("Total number of files  : %d\n"), TotalFileCount);
307   _tprintf (_T("Total number of lines  : %d\n"), TotalLineCount);
308   _tprintf (_T("Average no. lines/file : %d\n"), TotalAvgLF);
309 }
310
311
312 BOOL
313 ProcessFiles(LPTSTR Path)
314 {
315   WIN32_FIND_DATA FindFile;
316   PEXTENSION_INFO Info;
317   TCHAR SearchPath[256];
318   TCHAR FileName[256];
319   HANDLE SearchHandle;
320   BOOL More;
321
322   Info = ExtInfoList;
323   while (Info != NULL)
324   {
325     ZeroMemory (&FindFile, sizeof (FindFile));
326     _tcscpy (SearchPath, Path);
327     _tcscat (SearchPath, _T("\\*."));
328     _tcscat (SearchPath, Info->ExtName);
329     _tcscpy (FindFile.cFileName, SearchPath);
330     SearchHandle = FindFirstFile (SearchPath, &FindFile);
331     if (SearchHandle != INVALID_HANDLE_VALUE)
332     {
333       More = TRUE;
334       while (More)
335       {
336               if (!(FindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
337             {
338           _tcscpy (FileName, Path);
339           _tcscat (FileName, _T("\\"));
340           _tcscat (FileName, FindFile.cFileName);
341
342                                   if (LoadFile (FileName))
343                                   {
344                   PFILE_INFO StatInfo;
345         
346                   StatInfo = AddFile (FindFile.cFileName, Info);
347                   if (!StatInfo)
348                                                 {
349                                     _tprintf (_T("Not enough free memory.\n"));
350                     return FALSE;
351                                                 }
352         
353                                     DoStatisticsForFile (StatInfo);
354         
355             Info->FileCount++;
356                   Info->LineCount += StatInfo->LineCount;
357
358                   CleanupAfterFile();
359                                   }
360         }
361         More = FindNextFile (SearchHandle, &FindFile);
362       }
363       FindClose (SearchHandle);
364     }
365     Info = Info->Next;
366   }
367   return TRUE;
368 }
369
370
371 BOOL
372 ProcessDirectories(LPTSTR Path)
373 {
374   WIN32_FIND_DATA FindFile;
375   TCHAR SearchPath[MAX_PATH];
376   HANDLE SearchHandle;
377   BOOL More;
378
379         _tprintf (_T("Processing directory %s\n"), Path);
380
381   _tcscpy (SearchPath, Path);
382   _tcscat (SearchPath, _T("\\*.*"));
383
384   SearchHandle = FindFirstFileEx (SearchPath,
385     FindExInfoStandard,
386     &FindFile,
387     FindExSearchLimitToDirectories,
388     NULL,
389     0);
390   if (SearchHandle != INVALID_HANDLE_VALUE)
391   {
392     More = TRUE;
393     while (More)
394     {
395             if ((FindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
396       && (_tcscmp (FindFile.cFileName, _T(".")) != 0)
397       && (_tcscmp (FindFile.cFileName, _T("..")) != 0)
398       && (_tcscmp (FindFile.cFileName, _T("CVS")) != 0))
399                         {
400                           _tcscpy (SearchPath, Path);
401                           _tcscat (SearchPath, _T("\\"));
402                           _tcscat (SearchPath, FindFile.cFileName);
403               if (!ProcessDirectories (SearchPath))
404           return FALSE;
405               if (!ProcessFiles (SearchPath))
406           return FALSE;
407                         }
408       More = FindNextFile (SearchHandle, &FindFile);
409     }
410     FindClose (SearchHandle);
411   }
412   return TRUE;
413 }
414
415
416 VOID
417 Execute(LPTSTR Path)
418 {
419   if (!ExtInfoList)
420   {
421           _tprintf (_T("No extensions specified.\n"));
422     return;
423   }
424
425   if (!ProcessDirectories (Path))
426   {
427           _tprintf (_T("Failed to process directories.\n"));
428     return;
429   }
430
431   if (!ProcessFiles (Path))
432   {
433           _tprintf (_T("Failed to process files.\n"));
434     return;
435   }
436
437   PrintStatistics();
438 }
439
440
441 int
442 main (int argc, char * argv [])
443 {
444   _tprintf (_T("\nReactOS project statistics generator.\n\n"));
445
446   if (argc < 2)
447   {
448     _tprintf(_T("Usage: stats directory"));
449     return 1;
450   }
451
452   Initialize();
453   AddExtension (_T("c"), _T("Source files"));
454   AddExtension (_T("h"), _T("Header files"));
455   Execute (argv[1]);
456   Cleanup();
457
458   return 0;
459 }