1
+ #include <string.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <ctype.h>
5
+ #include <errno.h>
6
+ #include <stdbool.h>
7
+
8
+ const char lexacount_version [] = "1.0" ;
9
+
10
+ int is_quote (char * quotes_str , size_t qlen , int chr )
11
+ {
12
+ for (size_t i = 0 ; i < qlen ; i ++ )
13
+ {
14
+ if (chr == quotes_str [i ])
15
+ return true;
16
+ }
17
+ return false;
18
+ }
19
+
20
+ #define is_bracket is_quote
21
+
22
+ void show_version ()
23
+ {
24
+ printf ("LexaCount v%s - Count source lines of code.\n" , lexacount_version );
25
+ }
26
+
27
+ void help ()
28
+ {
29
+ show_version ();
30
+ printf (
31
+ "Usage:\n"
32
+ " lexacount [-b] [-t] [-l <list file>] [file1] [file2] ...\n\n"
33
+ "Switches:\n"
34
+ " -b, --bracket Do not count lines containing only brackets or parenthesis\n"
35
+ " -h, --help Display this help menu\n"
36
+ " -l, --list Load file names from a file\n"
37
+ " -t, --table Print the output using tables\n"
38
+ " -v, --version Display program version\n\n"
39
+ "Copyright (c) 2024 anic17 Software\n" );
40
+ }
41
+
42
+ void missing_param (char * s )
43
+ {
44
+ fprintf (stderr , "Error: Required parameter after '%s'. See 'lexacount --help' for more information.\n" , s );
45
+ exit (1 );
46
+ }
47
+
48
+ size_t count_loc (char * filename , char * * comments , char * quotes , char * brackets , size_t * file_loc , size_t * file_comment , size_t * file_blank , size_t * file_bracket , bool excludeBrackets )
49
+ {
50
+ * file_loc = 0 ;
51
+ * file_comment = 0 ;
52
+ * file_blank = 0 ;
53
+ * file_bracket = 0 ;
54
+ filename [strcspn (filename , "\r\n" )] = '\0' ;
55
+ if (filename [0 ] == '\0' )
56
+ {
57
+ return 0 ;
58
+ }
59
+ FILE * count_fp = fopen (filename , "rb" );
60
+ if (!count_fp )
61
+ {
62
+ fprintf (stderr , "%s: %s\n" , filename , strerror (errno ));
63
+ return 0 ;
64
+ }
65
+ bool isLineBlank = true;
66
+ bool isLineOnlyBrackets = false;
67
+ bool isFileEmpty = true;
68
+ int chr = 0 ;
69
+ size_t comment_idx = 0 ;
70
+ int quoteStatus = 0 ; // Status of the quotes
71
+ size_t qlen = strlen (quotes );
72
+ size_t blen = strlen (brackets );
73
+ size_t clen = strlen (comments [0 ]);
74
+
75
+ while ((chr = fgetc (count_fp )) != EOF )
76
+ {
77
+ isFileEmpty = false;
78
+ if (is_quote (quotes , qlen , chr ))
79
+ {
80
+ quoteStatus ^= chr ;
81
+ }
82
+ if (isLineBlank && !quoteStatus )
83
+ {
84
+ if (comment_idx >= clen - 1 )
85
+ {
86
+ ++ (* file_comment );
87
+ comment_idx = 0 ;
88
+ continue ;
89
+ }
90
+ if (chr == comments [0 ][comment_idx ])
91
+ {
92
+ comment_idx ++ ;
93
+ continue ;
94
+ }
95
+ }
96
+
97
+ if ((!isspace (chr ) || (!is_bracket (brackets , blen , chr ) && excludeBrackets )))
98
+ {
99
+ if (is_bracket (brackets , blen , chr ) && excludeBrackets )
100
+ {
101
+ isLineOnlyBrackets = true;
102
+ }
103
+ else
104
+ {
105
+ if (!isspace (chr ))
106
+ {
107
+ isLineBlank = false;
108
+ isLineOnlyBrackets = false;
109
+ }
110
+ }
111
+ }
112
+ if (chr == '\n' )
113
+ {
114
+ if (isLineOnlyBrackets && isLineBlank )
115
+ {
116
+ ++ (* file_bracket );
117
+ }
118
+ else if (isLineBlank )
119
+ {
120
+ ++ (* file_blank );
121
+ }
122
+
123
+ ++ (* file_loc );
124
+ isLineBlank = true;
125
+ isLineOnlyBrackets = false;
126
+ quoteStatus = 0 ;
127
+ comment_idx = 0 ;
128
+ }
129
+ }
130
+
131
+ if (!isFileEmpty )
132
+ {
133
+ if (isLineOnlyBrackets && isLineBlank )
134
+ {
135
+ ++ (* file_bracket );
136
+ }
137
+ else if (isLineBlank )
138
+ {
139
+ ++ (* file_blank );
140
+ }
141
+ ++ (* file_loc );
142
+ }
143
+
144
+ fclose (count_fp );
145
+ return * file_loc ;
146
+ }
147
+
148
+ void print_table_header (const char * formatspec , bool excludeBrackets )
149
+ {
150
+ printf ("| " );
151
+ printf (formatspec , "File" );
152
+ printf (" | %-10s | %-10s | %-10s |" , "Code lines" , "Blank" , "Comments" );
153
+
154
+ if (excludeBrackets )
155
+ {
156
+ printf (" %-15s |" , "Brackets only" );
157
+ }
158
+
159
+ printf ("\n" );
160
+ }
161
+
162
+ void print_table_separator (size_t flen , bool excludeBrackets )
163
+ {
164
+ printf ("|" );
165
+ for (size_t k = 0 ; k < flen + 2 ; k ++ )
166
+ {
167
+ printf ("-" );
168
+ }
169
+ printf ("|------------|------------|------------|" );
170
+
171
+ if (excludeBrackets )
172
+ {
173
+ printf ("-----------------|" );
174
+ }
175
+ printf ("\n" );
176
+ }
177
+
178
+ void print_table_row (const char * formatspec , const char * filename , size_t lines , size_t blanks , size_t comments , size_t brackets , bool excludeBrackets )
179
+ {
180
+ printf ("| " );
181
+ printf (formatspec , filename );
182
+ printf (" | %-10zu | %-10zu | %-10zu |" , excludeBrackets ? (lines - blanks - comments - brackets ) : (lines - blanks - comments ), blanks , comments );
183
+
184
+ if (excludeBrackets )
185
+ {
186
+ printf (" %-15zu |" , brackets );
187
+ }
188
+ printf ("\n" );
189
+ }
190
+
191
+ void display_lines (const char * formatspec , const char * filename , size_t file_loc , size_t file_blank , size_t file_comment , size_t file_bracket , bool tableOutput , bool excludeBrackets )
192
+ {
193
+ if (tableOutput )
194
+ {
195
+ print_table_row (formatspec , filename , file_loc , file_blank , file_comment , file_bracket , excludeBrackets );
196
+ }
197
+ else
198
+ {
199
+ printf ("%s: %zu lines" , filename , excludeBrackets ? (file_loc - file_blank - file_comment - file_bracket ) : (file_loc - file_blank - file_comment ));
200
+
201
+ if (file_blank > 0 || file_comment > 0 || file_bracket > 0 )
202
+ {
203
+ printf (" (excluding" );
204
+
205
+ if (file_blank > 0 )
206
+ {
207
+ printf (" %zu blank line%s" , file_blank , (file_blank == 1 ) ? "" : "s" );
208
+ }
209
+
210
+ if (file_comment > 0 )
211
+ {
212
+ printf ("%s%zu comment%s" , (file_blank > 0 ) ? " and " : " " , file_comment , (file_comment == 1 ) ? "" : "s" );
213
+ }
214
+
215
+ if (file_bracket > 0 && excludeBrackets )
216
+ {
217
+ printf ("%s%zu line%s with only brackets" , ((file_blank > 0 ) || (file_comment > 0 )) ? " and " : " " , file_bracket , (file_bracket == 1 ) ? "" : "s" );
218
+ }
219
+
220
+ printf (")" );
221
+ }
222
+ printf ("\n" );
223
+ }
224
+ }
225
+
226
+ int main (int argc , char * argv [])
227
+ {
228
+ char quotechars [] = "'\"" ;
229
+ char bracketchars [] = "{}[]()" ;
230
+ if (argc < 2 || !strcmp (argv [1 ], "--help" ) || !strcmp (argv [1 ], "/?" ))
231
+ {
232
+ help ();
233
+ return 0 ;
234
+ }
235
+ char * loc_file = argv [1 ];
236
+ FILE * list ;
237
+
238
+ char * comments [] = {"//" };
239
+
240
+ char * * fnames = calloc (argc - 1 , sizeof (char * )), * * list_fnames = calloc (argc - 1 , sizeof (char * ));
241
+ size_t fname_count = 0 , list_fname_count = 0 ;
242
+
243
+ size_t longest_fname = 0 ;
244
+
245
+ bool excludeBrackets = false;
246
+ bool tableOutput = false;
247
+ for (int i = 1 ; i < argc ; i ++ )
248
+ {
249
+ if (!strcmp (argv [i ], "-l" ) || !strcmp (argv [i ], "--list" ))
250
+ {
251
+ if (i + 1 < argc )
252
+ {
253
+ if (argv [i ] != NULL )
254
+ {
255
+ list_fnames [list_fname_count ] = calloc (strlen (argv [i + 1 ]) + 1 , sizeof (char ));
256
+ memcpy (list_fnames [list_fname_count ], argv [i + 1 ], strlen (argv [i + 1 ]));
257
+ if (strlen (list_fnames [list_fname_count ]) > longest_fname )
258
+ {
259
+ longest_fname = strlen (list_fnames [list_fname_count ]);
260
+ }
261
+ list_fname_count ++ ;
262
+ }
263
+ i ++ ;
264
+ }
265
+ else
266
+ {
267
+ missing_param (argv [i ]);
268
+ }
269
+ }
270
+
271
+ else if (!strcmp (argv [i ], "-b" ) || !strcmp (argv [i ], "--bracket" ))
272
+ {
273
+ excludeBrackets = true;
274
+ }
275
+ else if (!strcmp (argv [i ], "-t" ) || !strcmp (argv [i ], "--table" ))
276
+ {
277
+ tableOutput = true;
278
+ }
279
+ else if (!strcmp (argv [i ], "-v" ) || !strcmp (argv [i ], "--version" ))
280
+ {
281
+ show_version ();
282
+ printf ("\nCopyright (c) 2024 anic17 Software\n" );
283
+ exit (0 );
284
+ }
285
+
286
+ else
287
+ {
288
+ if (argv [i ] != NULL )
289
+ {
290
+ fnames [fname_count ] = calloc (strlen (argv [i ]) + 1 , sizeof (char ));
291
+ memcpy (fnames [fname_count ], argv [i ], strlen (argv [i ]));
292
+ if (strlen (fnames [fname_count ]) > longest_fname )
293
+ {
294
+ longest_fname = strlen (fnames [fname_count ]);
295
+ }
296
+ fname_count ++ ;
297
+ }
298
+ }
299
+ }
300
+
301
+ size_t total_loc = 0 , total_comment_loc = 0 , total_blank_loc = 0 , total_bracket_loc = 0 ;
302
+ size_t file_loc = 0 , file_comment_loc = 0 , file_blank_loc = 0 , file_bracket_loc = 0 ;
303
+ size_t file_count = 0 ;
304
+
305
+ char filename [512 ];
306
+
307
+ if (longest_fname < 11 )
308
+ {
309
+ longest_fname = 11 ;
310
+ }
311
+
312
+ char * fspec = calloc (sizeof (char ), longest_fname + 10 );
313
+ snprintf (fspec , longest_fname , "%%-%zus" , longest_fname );
314
+
315
+ if (tableOutput )
316
+ {
317
+ print_table_header (fspec , excludeBrackets );
318
+ print_table_separator (longest_fname , excludeBrackets );
319
+ }
320
+ for (size_t i = 0 ; i < list_fname_count ; i ++ )
321
+ {
322
+ list = fopen (list_fnames [i ], "rb" );
323
+ if (!list )
324
+ {
325
+ fprintf (stderr , "%s: %s" , loc_file , strerror (errno ));
326
+ return errno ;
327
+ }
328
+ while (fgets (filename , sizeof filename , list ))
329
+ {
330
+ count_loc (filename , comments , quotechars , bracketchars , & file_loc , & file_comment_loc , & file_blank_loc , & file_bracket_loc , excludeBrackets );
331
+ display_lines (fspec , filename , file_loc , file_blank_loc , file_comment_loc , file_bracket_loc , tableOutput , excludeBrackets );
332
+ file_count ++ ;
333
+ total_loc += file_loc ;
334
+ total_comment_loc += file_comment_loc ;
335
+ total_blank_loc += file_blank_loc ;
336
+ total_bracket_loc += file_bracket_loc ;
337
+ }
338
+ fclose (list );
339
+ }
340
+
341
+ for (size_t i = 0 ; i < fname_count ; i ++ )
342
+ {
343
+ count_loc (fnames [i ], comments , quotechars , bracketchars , & file_loc , & file_comment_loc , & file_blank_loc , & file_bracket_loc , excludeBrackets );
344
+ display_lines (fspec , fnames [i ], file_loc , file_blank_loc , file_comment_loc , file_bracket_loc , tableOutput , excludeBrackets );
345
+ file_count ++ ;
346
+ total_loc += file_loc ;
347
+ total_comment_loc += file_comment_loc ;
348
+ total_blank_loc += file_blank_loc ;
349
+ total_bracket_loc += file_bracket_loc ;
350
+ }
351
+ if (tableOutput )
352
+ {
353
+ print_table_separator (longest_fname , excludeBrackets );
354
+ }
355
+ display_lines (fspec , "Total lines" , total_loc , total_blank_loc , total_comment_loc , total_bracket_loc , tableOutput , excludeBrackets );
356
+ free (fspec );
357
+ free (list_fnames );
358
+ free (fnames );
359
+ return 0 ;
360
+ }
0 commit comments