1
+ ; I know; lines of code aren't a good metric, blah blah blah
2
+ ; I would still like to know how many I've written :)
3
+ ; This script isn't perfect and I'm sure there's many other/simpler ways to do this, but if that appealed to me, would I be writing an OS? :P
4
+
5
+ TotalFiles := 0
6
+ TotalDirectories := 0
7
+ SourceFiles := 0
8
+ SourceFilesCounted := 0
9
+ NonSourceExts = dll
10
+ ExtensionsToParse = cs,c,cpp,h,ahk,hpp,cc
11
+ ; ExcludeFolders = SDL,My-Doom
12
+ SourceOnlyLines := 0
13
+ CommentOnlyLines := 0
14
+ SourceLinesWithComments := 0
15
+ BlankLines := 0
16
+ BracesOnlyLines := 0
17
+ SkippedLines := 0
18
+ TODOs := 0
19
+ HACKs := 0
20
+ Directories :=
21
+ SourceFileList :=
22
+ Comments :=
23
+
24
+ SetWorkingDir , %A_ScriptDir %\..
25
+
26
+ ; Determine how many files and directories we need to scan
27
+ Loop , Files, * , DFR
28
+ {
29
+ ; Don't include files or folders which mostly contain source I didn't write
30
+ IfInString , A_LoopFileFullPath ,SDL\
31
+ continue
32
+ IfInString A_LoopFileFullPath ,My- Doom\
33
+ continue
34
+ IfInString A_LoopFileFullPath ,.git
35
+ continue
36
+ IfInString A_LoopFileFullPath ,.vs
37
+ continue
38
+ IfInString A_LoopFileFullPath ,font
39
+ continue
40
+ IfInString A_LoopFileFullPath ,spf
41
+ continue
42
+ IfInString A_LoopFileFullPath ,Debug
43
+ continue
44
+ IfInString A_LoopFileFullPath ,Release
45
+ continue
46
+ IfInString A_LoopFileFullPath ,x64
47
+ continue
48
+
49
+ ; Don't include generated files
50
+ IfInString , A_LoopFileFullPath ,TemporaryGeneratedFile
51
+ continue
52
+
53
+ FileGetAttrib , Attributes, %A_LoopFileFullPath %
54
+ IfInString , Attributes, D
55
+ {
56
+ TotalDirectories + = 1
57
+ Directories := Directories . " `r`n" . A_LoopFileFullPath
58
+ }
59
+ else
60
+ {
61
+ TotalFiles + = 1
62
+
63
+ if A_LoopFileExt in %ExtensionsToParse%
64
+ {
65
+ SourceFiles + = 1
66
+ SourceFileList := SourceFileList . " `r`n" . A_LoopFileFullPath
67
+ }
68
+ else
69
+ {
70
+ if (A_LoopFileExt <> "" )
71
+ {
72
+ if A_LoopFileExt not in %NonSourceExts%
73
+ NonSourceExts = %NonSourceExts%,%A_LoopFileExt %
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ ; Display a window with a progress bar
80
+ ; totalEverything := TotalFiles + TotalDirectories
81
+ Progress , R0- %SourceFiles%, %a_index %, %a_loopfilename %, Counting..., Counting Lines
82
+ Loop , Files, * , DFR
83
+ {
84
+ Progress , %SourceFilesCounted%, %a_loopfilename %, Counting..., Counting Lines
85
+ IfNotInString , Attributes, D
86
+ {
87
+ ; Don't include files or folders which mostly contain source I didn't write
88
+ IfInString , A_LoopFileFullPath ,SDL\
89
+ continue
90
+ IfInString A_LoopFileFullPath ,My- Doom\
91
+ continue
92
+ IfInString A_LoopFileFullPath ,.git
93
+ continue
94
+ IfInString A_LoopFileFullPath ,.vs
95
+ continue
96
+ IfInString A_LoopFileFullPath ,font
97
+ continue
98
+ IfInString A_LoopFileFullPath ,spf
99
+ continue
100
+ IfInString A_LoopFileFullPath ,Debug
101
+ continue
102
+ IfInString A_LoopFileFullPath ,Release
103
+ continue
104
+ IfInString A_LoopFileFullPath ,x64
105
+ continue
106
+
107
+ ; Don't include generated files
108
+ IfInString , A_LoopFileFullPath ,TemporaryGeneratedFile
109
+ continue
110
+
111
+ if A_LoopFileExt in %ExtensionsToParse%
112
+ {
113
+ CountLines(A_LoopFileFullPath )
114
+ SourceFilesCounted + = 1
115
+ }
116
+ else
117
+ {
118
+ if (A_LoopFileExt <> "" )
119
+ {
120
+ if A_LoopFileExt not in %NonSourceExts%
121
+ NonSourceExts = %NonSourceExts%,%A_LoopFileExt %
122
+ }
123
+ }
124
+ }
125
+ }
126
+ Progress , Off
127
+
128
+ ; Format number with comma (From https://autohotkey.com/board/topic/41587-question-about-formating-numbers-1000-to-1000-how/ )
129
+ VarSetCapacity ( StringLines,32 )
130
+ DllCall ( " GetNumberFormat" ,UInt,0x0409 ,UInt,0 ,Str,SourceOnlyLines,UInt,0 ,Str,StringLines,Int,32 )
131
+ StringTrimRight , StringLines, StringLines, 3
132
+ ; MsgBox, % StringLines
133
+
134
+ ; MsgBox %Directories%
135
+ CountSummary :=
136
+ CountSummary .= NumericalFormat(SourceOnlyLines + SourceLinesWithComments + CommentOnlyLines) . " Total Unique and meaningful lines`r`r"
137
+ CountSummary .= NumericalFormat(SourceOnlyLines + SourceLinesWithComments) . " Total lines with code`r"
138
+ CountSummary .= NumericalFormat(CommentOnlyLines + SourceLinesWithComments) . " Total lines with comments`r`r"
139
+ CountSummary .= NumericalFormat(SourceOnlyLines) . " lines with only code`r"
140
+ CountSummary .= NumericalFormat(SourceLinesWithComments) . " lines with comments and code`r"
141
+ CountSummary .= NumericalFormat(CommentOnlyLines) . " lines with only comments`r"
142
+ CountSummary .= NumericalFormat(BracesOnlyLines) . " lines with only braces`r"
143
+ CountSummary .= NumericalFormat(BlankLines) . " blank lines"
144
+
145
+ CommentOnlyLines := 0
146
+ SourceLinesWithComments := 0
147
+ BlankLines := 0
148
+ BracesOnlyLines := 0
149
+
150
+ ; This can be used for debugging. Here I've set it out to show me lines with comments and code:
151
+ ; Gui, Add, Edit, R50 w900 Multi vListingBox
152
+ ; GuiControl,, ListingBox, %Comments%
153
+ ; GuiControl,, ListingBox, %Directories%
154
+ ; Gui, Show
155
+
156
+ MsgBox Results of scanning %A_WorkingDir %:`r`r%CountSummary%`r%TODOs% TODOs`r%HACKs% HACKs`r`rCounted in `r%TotalDirectories% directories`r%SourceFiles% source files
157
+ ; `rNon-Source files with extensions of %NonSourceExts%
158
+ ExitApp ; Replace this with return during development
159
+
160
+
161
+ CountLines(sourceFile)
162
+ {
163
+ global
164
+ local line
165
+ local inComment := false
166
+ local maxLines := 0
167
+
168
+ hasComment := false
169
+
170
+ Loop , Read , %sourceFile%
171
+ {
172
+ MaxLines + = 1
173
+ }
174
+
175
+ ; Progress, R1-%MaxLines%, , %a_loopfilename%, Counting..., Counting Lines
176
+ Loop , Read , %sourceFile%
177
+ {
178
+
179
+ ; Progress, %A_Index%, %A_Index%, Counting..., Counting %sourceFile% - %A_Index%
180
+ line := Trim (A_LoopReadLine )
181
+ if (line <> "" )
182
+ {
183
+ inComment := DetermineIfInComment(line, inComment)
184
+
185
+ ; MsgBox %line%`r%inComment%
186
+
187
+ if (inComment)
188
+ {
189
+ ; MsgBox In Comment
190
+ if (hasCode)
191
+ {
192
+ SourceLinesWithComments + = 1
193
+ Comments .= " `r`n" . line
194
+ }
195
+ else
196
+ CommentOnlyLines + = 1
197
+ }
198
+ else
199
+ {
200
+ ; not in a comment
201
+ if (hasComment)
202
+ {
203
+ if (hasCode)
204
+ {
205
+ SourceLinesWithComments + = 1
206
+ Comments .= " `r`n" . line
207
+ }
208
+ else
209
+ {
210
+ CommentOnlyLines + = 1
211
+ ; Comments .= "`r`n" . line
212
+ }
213
+
214
+ }
215
+ else
216
+ {
217
+ ; no multi-block comments started here.
218
+ ; check for bracket-only lines
219
+ if (line <> " }" and line <> " {" and line <> " };" )
220
+ {
221
+ ; line has more than brackets, check for inline comments
222
+ IfInString , line,//
223
+ {
224
+ if (InStr (line, " //" ) = 1 )
225
+ CommentOnlyLines + = 1
226
+ else
227
+ {
228
+ SourceLinesWithComments + = 1
229
+ Comments .= " `r`n" . line
230
+ }
231
+ }
232
+ else
233
+ {
234
+ SourceOnlyLines + = 1
235
+ }
236
+
237
+ IfInString line,HACK
238
+ HACKs + = 1
239
+ IfInString line,TODO
240
+ TODOs + = 1
241
+ }
242
+ else
243
+ BracesOnlyLines + = 1
244
+ }
245
+ }
246
+ }
247
+ else
248
+ BlankLines + = 1
249
+ }
250
+ }
251
+
252
+ NumericalFormat(num)
253
+ {
254
+ local returnString
255
+ ; Format number with comma (From https://autohotkey.com/board/topic/41587-question-about-formating-numbers-1000-to-1000-how/ )
256
+ VarSetCapacity ( returnString,32 )
257
+ DllCall ( " GetNumberFormat" ,UInt,0x0409 ,UInt,0 ,Str,num,UInt,0 ,Str,returnString,Int,32 )
258
+ StringTrimRight , returnString, returnString, 3
259
+ ; MsgBox, % StringLines
260
+ return returnString
261
+ }
262
+
263
+ DetermineIfInComment(line, inComment)
264
+ {
265
+ beginComment := " /*"
266
+ endComment := " */"
267
+ global hasCode := false
268
+ global hasComment := false
269
+ while ( strlen (line) <> 0 )
270
+ {
271
+ if (inComment)
272
+ {
273
+ ; get the next occurrence of end comment
274
+ StringGetPos , EndPos, line,%endComment%
275
+ if (ErrorLevel = 1 )
276
+ {
277
+ ; couldn't find end of comment, so we're still in a comment
278
+ hasComment := true
279
+ return true
280
+ }
281
+
282
+ if (EndPos <> 0 )
283
+ hasComment := true
284
+
285
+ inComment := false
286
+
287
+ endPos + = 3
288
+
289
+ ; msgbox %line%`rEnd: %endpos%
290
+ line := SubStr (line, EndPos)
291
+ ; msgBox %line%
292
+ }
293
+ else
294
+ {
295
+ ; check for the next occurrence of begin comment
296
+ StringGetPos , BeginPos, line,%beginComment%
297
+ if (ErrorLevel = 1 )
298
+ {
299
+ ; couldn't find beginning of comment, so we aren't in a comment
300
+ hasCode := true
301
+ return false
302
+ }
303
+
304
+ if (BeginPos <> 0 )
305
+ hasCode := true
306
+
307
+ BeginPos + = 3
308
+
309
+ inComment := true
310
+
311
+ ; length := strlen(line) - BeginPos
312
+ ; msgbox %line%`rBegin: %beginpos%`rLength: %Length%
313
+ line := SubStr (line, BeginPos)
314
+ ; msgBox %line%
315
+ }
316
+ }
317
+ return inComment
318
+ }
319
+
320
+ ; Super-useful: reload the script everytime I press ctrl-s (every time I save the script I re-run it)
321
+ ~^s ::
322
+ Reload
323
+ Exit
0 commit comments