Adding wcr - recursive wc
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
Resursive wc :)
|
||||
|
||||
// A
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user