lcc/lcc.c

178 lines
5.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include "lcc.h"
#define BUFFER_SIZE 8192
#define NUM_LANGS sizeof(languages) / sizeof(language)
typedef struct {
const char *name;
int files;
int lines;
int blanks;
int comments;
} lang_stats;
lang_stats stats[NUM_LANGS] = {0};
void count_lines(const char *filename, language *lang, lang_stats *stat)
{
FILE *file = fopen(filename, "r");
if (!file) {
perror("fopen");
return;
}
char buffer[BUFFER_SIZE];
int in_comment = 0;
while (fgets(buffer, BUFFER_SIZE, file)) {
stat->lines++;
char *line = buffer;
while (isspace(*line)) line++; /* Skip leading whitespace */
if (*line == '\0') {
stat->blanks++;
continue;
}
if (in_comment) {
char *end = strstr(line, lang->block_comment_end);
if (end) {
in_comment = 0;
line = end + strlen(lang->block_comment_end);
stat->comments++;
} else {
stat->comments++;
continue;
}
}
if (lang->line_comment && strncmp(line, lang->line_comment, strlen(lang->line_comment)) == 0) {
stat->comments++;
} else if (lang->block_comment_start && strstr(line, lang->block_comment_start) != NULL) {
char *start = strstr(line, lang->block_comment_start);
char *end = strstr(start + strlen(lang->block_comment_start), lang->block_comment_end);
if (end) {
stat->comments++;
line = end + strlen(lang->block_comment_end);
} else {
in_comment = 1;
stat->comments++;
}
}
}
fclose(file);
}
void process_directory(const char *dirname)
{
struct dirent *entry;
DIR *dp = opendir(dirname);
if (!dp) {
perror("opendir");
return;
}
char path[PATH_MAX];
struct stat info;
while ((entry = readdir(dp))) {
if (entry->d_name[0] == '.') continue; /* Skip hidden files and directories */
int skip = 0;
/* not count ignore folders */
for (int i = 0; i < IGNORE_DIRS; i++) {
if (strstr(entry->d_name, ignore_dir[i]) != NULL) {
skip = 1;
break;
}
}
if (skip) continue;
snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);
if (stat(path, &info) == -1) {
perror("stat");
continue;
}
if (S_ISDIR(info.st_mode)) {
process_directory(path);
} else {
for (size_t i = 0; i < NUM_LANGS; i++) {
for (int j = 0; languages[i].extensions[j] != NULL; j++) {
char *ext = strstr(entry->d_name, ".");
if (strcmp(ext ? ext : entry->d_name, languages[i].extensions[j]) == 0) {
stats[i].files++;
count_lines(path, &languages[i], &stats[i]);
break;
}
}
}
}
}
closedir(dp);
}
int compare_stats(const void *a, const void *b) {
lang_stats *a_stats = (lang_stats *) a;
lang_stats *b_stats = (lang_stats *) b;
int a_code_lines = a_stats->lines - a_stats->blanks - a_stats->comments;
int b_code_lines = b_stats->lines - b_stats->blanks - b_stats->comments;
return b_code_lines - a_code_lines;
}
int main(int argc, char **argv)
{
if (argc == 2 && strncmp(argv[1], "-h", 2) == 0) {
fprintf(stderr, "lcc - Lines of Code Counter\n\nUsage: lcc <path> <path2> <path3> - Count lines of code in supplied paths(no argument would be considered counting in current directory)\n");
return 0;
}
for (size_t i = 0; i < NUM_LANGS; i++) {
stats[i].name = languages[i].name;
}
if (argc < 2) {
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) == NULL) {
perror("getcwd");
return 1;
}
process_directory(cwd);
} else {
for (int i = 1; i < argc; i++) {
process_directory(argv[i]);
}
}
qsort(stats, NUM_LANGS, sizeof(lang_stats), compare_stats);
printf("%-10s %-6s %-6s %-8s %-6s %-6s\n", "Language", "Files", "Code", "Comment", "Blank", "Lines");
lang_stats total_stats = {0};
for (size_t i = 0; i < NUM_LANGS; i++) {
if (stats[i].files > 0) {
int code_lines = stats[i].lines - stats[i].blanks - stats[i].comments;
total_stats.files += stats[i].files;
total_stats.lines += stats[i].lines;
total_stats.comments += stats[i].comments;
total_stats.blanks += stats[i].blanks;
printf("%-10s %-6d %-6d %-8d %-6d %-6d\n", stats[i].name, stats[i].files, code_lines, stats[i].comments, stats[i].blanks, stats[i].lines);
}
}
int total_code_lines = total_stats.lines - total_stats.blanks - total_stats.comments;
printf("%-10s %-6d %-6d %-8d %-6d %-6d\n", "Total", total_stats.files, total_code_lines, total_stats.comments, total_stats.blanks, total_stats.lines);
return 0;
}