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