Temporary working code
This commit is contained in:
parent
3c24cbc268
commit
5affb35b93
2 changed files with 234 additions and 0 deletions
175
lcc.c
Normal file
175
lcc.c
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
#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};
|
||||||
|
lang_stats total_stats = {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++;
|
||||||
|
total_stats.lines++;
|
||||||
|
char *line = buffer;
|
||||||
|
while (isspace(*line)) line++; // Skip leading whitespace
|
||||||
|
|
||||||
|
if (*line == '\0') {
|
||||||
|
stat->blanks++;
|
||||||
|
total_stats.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++;
|
||||||
|
total_stats.comments++;
|
||||||
|
} else {
|
||||||
|
stat->comments++;
|
||||||
|
total_stats.comments++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lang->line_comment && strncmp(line, lang->line_comment, strlen(lang->line_comment)) == 0) {
|
||||||
|
stat->comments++;
|
||||||
|
total_stats.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++;
|
||||||
|
total_stats.comments++;
|
||||||
|
line = end + strlen(lang->block_comment_end);
|
||||||
|
} else {
|
||||||
|
in_comment = 1;
|
||||||
|
stat->comments++;
|
||||||
|
total_stats.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;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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++;
|
||||||
|
total_stats.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)
|
||||||
|
{
|
||||||
|
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", "Total");
|
||||||
|
printf("%-10s %-6d %-6d %-8d %-6d %-6d\n", "Total", total_stats.files, total_stats.lines - total_stats.comments - total_stats.blanks, total_stats.comments, total_stats.blanks, total_stats.lines);
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
59
lcc.h
Normal file
59
lcc.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef LCC_H_H
|
||||||
|
#define LCC_H_H
|
||||||
|
|
||||||
|
#define MAX_EXTENSIONS 10
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const char *extensions[MAX_EXTENSIONS];
|
||||||
|
const char *block_comment_start;
|
||||||
|
const char *block_comment_end;
|
||||||
|
const char *line_comment;
|
||||||
|
} language;
|
||||||
|
|
||||||
|
language languages[] = {
|
||||||
|
{"Ada", {".adb", ".ads"}, NULL, NULL, "--"},
|
||||||
|
{"Assembly", {".s"}, "/*", "*/", "#"},
|
||||||
|
{"C", {".c"}, "/*", "*/", "//"},
|
||||||
|
{"C++", {".cc", ".cpp", ".hh", ".hpp"}, "/*", "*/", "//"},
|
||||||
|
{"Clojure", {".clj", ".edn"}, NULL, NULL, ";"},
|
||||||
|
{"COBOL", {".cbl"}, NULL, NULL, "*>"},
|
||||||
|
{"CSS", {".css"}, "/*", "*/", NULL},
|
||||||
|
{"D", {".d"}, "/*", "*/", "//"},
|
||||||
|
{"Emacs Lisp", {".el"}, NULL, NULL, ";;"},
|
||||||
|
{"Erlang", {".erl", ".hrl"}, NULL, NULL, "%"},
|
||||||
|
{"Fortran", {".f77", ".f95"}, NULL, NULL, "!"},
|
||||||
|
{"Go", {".go"}, "/*", "*/", "//"},
|
||||||
|
{"Haskell", {".hs", ".lhs"}, "{-", "-}", "--",},
|
||||||
|
{"C Header", {".h"}, "/*", "*/", "//"},
|
||||||
|
{"HTML", {".htm", ".html"}, "<!--", "-->", NULL},
|
||||||
|
{"Java", {".java"}, "/*", "*/", "//"},
|
||||||
|
{"JavaScript", {".js"}, "/*", "*/", "//"},
|
||||||
|
{"Julia", {".jl"}, NULL, NULL, "#"},
|
||||||
|
{"LaTeX", {".tex", ".sty"}, NULL, NULL, "%"},
|
||||||
|
{"Kotlin", {".kt"}, "/*", "*/", "//"},
|
||||||
|
{"Lisp", {".lsp", ".lisp"}, NULL, NULL, ";"},
|
||||||
|
{"Lua", {".lua"}, "--[[", "]]", "--"},
|
||||||
|
{"Makefile", {"Makefile",".mk"}, NULL, NULL, "#"},
|
||||||
|
{"Objective-C", {".m"}, "/*", "*/", "//"},
|
||||||
|
{"OCaml", {".ml"}, "(*", "*)", NULL},
|
||||||
|
{"Pascal", {".pas"}, "{", "}", NULL},
|
||||||
|
{"Perl", {".pl", ".pm"}, NULL, NULL, "#"},
|
||||||
|
{"PHP", {".php"}, "/*", "*/", "//"},
|
||||||
|
{"Python", {".py"}, "\"\"\"", "\"\"\"", "#"},
|
||||||
|
{"R", {".r", ".R"}, NULL, NULL, "#"},
|
||||||
|
{"Ruby", {".rb", ".rbw"}, NULL, NULL, "#"},
|
||||||
|
{"Scala", {".scala"}, "/*", "*/", "//"},
|
||||||
|
{"Scheme", {".scm"}, NULL, NULL, ";"},
|
||||||
|
{"Shell", {".sh", ".bash"}, NULL, NULL, "#"},
|
||||||
|
{"SQL", {".sql"}, "/*", "*/", "--"},
|
||||||
|
{"TypeScript", {".ts",".tsx"}, "/*", "*/", "//"},
|
||||||
|
{"Vimscript", {".vim"}, NULL, NULL, "\""},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IGNORE_DIRS 5
|
||||||
|
/* IGNORE_DIRS must have same length of ignore_dir */
|
||||||
|
|
||||||
|
char *ignore_dir[IGNORE_DIRS] = {"stagit", "env", "TerminalChat", "cath-docs", ".d.ts"};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue