#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; }