Adding wcr - recursive wc

This commit is contained in:
2026-04-08 16:48:16 +02:00
parent a85b8f1f65
commit ed2a8cdede
3 changed files with 150 additions and 0 deletions
+10
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
Resursive wc :)
// A
+137
View File
@@ -0,0 +1,137 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fnmatch.h>
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;
}