Skip to content

Commit 23a5602

Browse files
authored
LexaCount v1.0 - First release
1 parent 44a8a54 commit 23a5602

File tree

1 file changed

+360
-0
lines changed

1 file changed

+360
-0
lines changed

lexacount.c

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
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

Comments
 (0)