diff --git a/wcr/Makefile b/wcr/Makefile new file mode 100644 index 0000000..68cd6a2 --- /dev/null +++ b/wcr/Makefile @@ -0,0 +1,10 @@ +CC = cc +CFLAGS = -Wall -Wextra -O2 + +wcr: wcr.c + $(CC) $(CFLAGS) -o wcr wcr.c + +clean: + rm -f wcr + +.PHONY: clean diff --git a/wcr/README.md b/wcr/README.md new file mode 100644 index 0000000..1caf7eb --- /dev/null +++ b/wcr/README.md @@ -0,0 +1,3 @@ +Resursive wc :) + +// A diff --git a/wcr/wcr.c b/wcr/wcr.c new file mode 100644 index 0000000..a6172fd --- /dev/null +++ b/wcr/wcr.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include + +typedef struct { long lines, words, chars; } Counts; + +static int show_lines, show_words, show_chars; + +static void count_file(const char *path, Counts *c) { + FILE *f = fopen(path, "r"); + if (!f) { perror(path); return; } + int ch, in_word = 0; + while ((ch = fgetc(f)) != EOF) { + c->chars++; + if (ch == '\n') c->lines++; + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') { + in_word = 0; + } else if (!in_word) { + in_word = 1; + c->words++; + } + } + fclose(f); +} + +static void print_counts(const Counts *c, const char *label) { + if (show_lines) printf(" %7ld", c->lines); + if (show_words) printf(" %7ld", c->words); + if (show_chars) printf(" %7ld", c->chars); + printf(" %s\n", label); +} + +static void walk(const char *dir, const char **pats, int npat, Counts *total, int *n) { + DIR *d = opendir(dir); + if (!d) { perror(dir); return; } + struct dirent *e; + while ((e = readdir(d))) { + if (e->d_name[0] == '.') continue; + char path[4096]; + snprintf(path, sizeof(path), "%s/%s", dir, e->d_name); + struct stat st; + if (stat(path, &st) < 0) continue; + if (S_ISDIR(st.st_mode)) { + walk(path, pats, npat, total, n); + } else if (S_ISREG(st.st_mode)) { + for (int i = 0; i < npat; i++) { + if (fnmatch(pats[i], e->d_name, 0) == 0) { + Counts c = {0}; + count_file(path, &c); + print_counts(&c, path); + total->lines += c.lines; + total->words += c.words; + total->chars += c.chars; + (*n)++; + break; + } + } + } + } + closedir(d); +} + +int main(int argc, char *argv[]) { + int recursive = 0; + const char **pats = NULL; + int npat = 0; + + for (int i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + for (char *f = argv[i] + 1; *f; f++) { + switch (*f) { + case 'l': show_lines = 1; break; + case 'w': show_words = 1; break; + case 'c': show_chars = 1; break; + case 'r': recursive = 1; break; + default: fprintf(stderr, "unknown flag: -%c\n", *f); return 1; + } + } + } else { + pats = realloc(pats, (npat + 1) * sizeof(char *)); + pats[npat++] = argv[i]; + } + } + + if (!show_lines && !show_words && !show_chars) + show_lines = show_words = show_chars = 1; + + if (npat == 0) { + fprintf(stderr, "usage: wcr [-lwcr] pattern...\n"); + return 1; + } + + Counts total = {0}; + int n = 0; + + if (recursive) { + /* For each pattern, split into dir + basename and walk from dir */ + for (int i = 0; i < npat; i++) { + char tmp[4096]; + strncpy(tmp, pats[i], sizeof(tmp) - 1); + tmp[sizeof(tmp) - 1] = '\0'; + char *slash = strrchr(tmp, '/'); + const char *dir, *base; + char dirbuf[4096]; + if (slash) { + *slash = '\0'; + dir = tmp; + base = slash + 1; + } else { + dir = "."; + base = pats[i]; + } + strncpy(dirbuf, dir, sizeof(dirbuf) - 1); + const char *bp = base; + walk(dirbuf, &bp, 1, &total, &n); + } + } else { + for (int i = 0; i < npat; i++) { + Counts c = {0}; + count_file(pats[i], &c); + print_counts(&c, pats[i]); + total.lines += c.lines; + total.words += c.words; + total.chars += c.chars; + n++; + } + } + + if (n > 1) + print_counts(&total, "total"); + + free(pats); + return 0; +}