--- fs.h | 17 ++++++++++-- grep.1 | 10 ++++--- grep.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++------- libutil/recurse.c | 51 +++++++++++++++++++++++++++++++++--- 4 files changed, 138 insertions(+), 18 deletions(-) diff --git a/fs.h b/fs.h index 15ae5f4..6e0a4fc 100644 --- a/fs.h +++ b/fs.h _AT_@ -2,25 +2,36 @@ #include <sys/stat.h> #include <sys/types.h> +#include "queue.h" + struct history { struct history *prev; dev_t dev; ino_t ino; }; +struct pendingrecurse { + char *path; + void *data; + int depth; + TAILQ_ENTRY(pendingrecurse) entry; +}; + struct recursor { - void (*fn)(const char *, struct stat *st, void *, struct recursor *); + void (*fn)(const char *, struct stat *, void *, struct recursor *); struct history *hist; int depth; int maxdepth; int follow; int flags; + TAILQ_HEAD(pending, pendingrecurse) pending; }; enum { SAMEDEV = 1 << 0, DIRFIRST = 1 << 1, SILENT = 1 << 2, + BFS = 1 << 3, }; extern int cp_aflag; _AT_@ -38,6 +49,8 @@ extern int rm_status; extern int recurse_status; void recurse(const char *, void *, struct recursor *); +void recurselater(const char *, void *, struct recursor *); +void recursenow(struct recursor *); int cp(const char *, const char *, int); -void rm(const char *, struct stat *st, void *, struct recursor *); +void rm(const char *, struct stat *, void *, struct recursor *); diff --git a/grep.1 b/grep.1 index 6f80175..90bcc1f 100644 --- a/grep.1 +++ b/grep.1 _AT_@ -1,4 +1,4 @@ -.Dd 2015-10-08 +.Dd 2016-03-30 .Dt GREP 1 .Os sbase .Sh NAME _AT_@ -6,7 +6,7 @@ .Nd search files for patterns .Sh SYNOPSIS .Nm -.Op Fl EFHchilnqsvx +.Op Fl EFHchilnqrsvx .Op Fl e Ar pattern .Op Fl f Ar file .Op Ar pattern _AT_@ -55,6 +55,10 @@ Print only the names of files with matching lines. Prefix each matching line with its line number in the input. .It Fl q Print nothing, only return status. +.It Fl r +Search directories recursively. If no +.Ar file +has been specified, the current working directory is searched. .It Fl s Suppress the error messages ordinarily written for nonexistent or unreadable files. _AT_@ -89,5 +93,5 @@ utility is compliant with the specification. .Pp The -.Op Fl Hhw +.Op Fl Hhrw flags are an extension to that specification. diff --git a/grep.c b/grep.c index 64ffbe2..0d2a8a6 100644 --- a/grep.c +++ b/grep.c _AT_@ -1,10 +1,15 @@ /* See LICENSE file for copyright and license details. */ +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> #include <regex.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> +#include "fs.h" #include "queue.h" #include "util.h" _AT_@ -21,12 +26,14 @@ static int eflag; static int fflag; static int hflag; static int iflag; +static int rflag; static int sflag; static int vflag; static int wflag; static int xflag; static int many; static int mode; +static int implicitcwd; struct pattern { char *pattern; _AT_@ -163,22 +170,60 @@ end: return match; } +static int +isdir(const char *path) +{ + struct stat st; + if (stat(path, &st)) + return 0; + return S_ISDIR(st.st_mode); +} + +static void +grepdir(const char *path, struct stat *st, void *data, struct recursor *r) +{ + int m, *match = data; + FILE *fp; + if (implicitcwd) { + if (path[0] == '.' && path[1] == '/') + path += 2; + } + if (S_ISDIR(st->st_mode)) { + recurselater(path, data, r); + return; + } + if (!(fp = fopen(path, "r"))) { + if (!sflag) + weprintf("fopen %s:", *path); + *match = Error; + return; + } + m = grep(fp, path); + if (m == Error || (*match != Error && m == Match)) + *match = m; + if (fshut(fp, path)) + *match = Error; +} + static void usage(void) { - enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f file] " + enprintf(Error, "usage: %s [-EFHchilnqrsvwx] [-e pattern] [-f file] " "[pattern] [file ...]\n", argv0); } int main(int argc, char *argv[]) { + struct recursor r = { .fn = grepdir, .hist = NULL, .depth = 0, .maxdepth = 0, + .follow = 'H', .flags = BFS }; struct pattern *pnode; int m, flags = REG_NOSUB, match = NoMatch; FILE *fp; char *arg; SLIST_INIT(&phead); + TAILQ_INIT(&r.pending); ARGBEGIN { case 'E': _AT_@ -226,8 +271,12 @@ main(int argc, char *argv[]) flags |= REG_ICASE; iflag = 1; break; + case 'r': + rflag = 1; + break; case 's': sflag = 1; + r.flags |= SILENT; break; case 'v': vflag = 1; _AT_@ -259,29 +308,40 @@ main(int argc, char *argv[]) /* Compile regex for all search patterns */ SLIST_FOREACH(pnode, &phead, entry) enregcomp(Error, &pnode->preg, pnode->pattern, flags); - many = (argc > 1); - if (argc == 0) { + many = (argc > 1) || rflag; + if (argc == 0 && !rflag) { match = grep(stdin, "<stdin>"); + } else if (argc == 0 && rflag) { + implicitcwd = 1; + recurse(".", &match, &r); } else { - for (; *argv; argc--, argv++) { + for (; argc; argc--, argv++) { if (!strcmp(*argv, "-")) { *argv = "<stdin>"; fp = stdin; + } else if (rflag && isdir(*argv)) { + fp = 0; } else if (!(fp = fopen(*argv, "r"))) { if (!sflag) weprintf("fopen %s:", *argv); match = Error; continue; } - m = grep(fp, *argv); - if (m == Error || (match != Error && m == Match)) - match = m; - if (fp != stdin && fshut(fp, *argv)) + if (fp) { + m = grep(fp, *argv); + if (m == Error || (match != Error && m == Match)) + match = m; + } else { + recurse(*argv, &match, &r); + } + if (fp && fp != stdin && fshut(fp, *argv)) match = Error; } } - if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>")) + recursenow(&r); + + if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>") | recurse_status) match = Error; return match; diff --git a/libutil/recurse.c b/libutil/recurse.c index e2b8a6e..bed4ed3 100644 --- a/libutil/recurse.c +++ b/libutil/recurse.c _AT_@ -96,12 +96,55 @@ recurse(const char *path, void *data, struct recursor *r) if (!(r->flags & DIRFIRST)) (r->fn)(path, &st, data, r); - for (; r->hist; ) { - h = r->hist; - r->hist = r->hist->prev; - free(h); + if (!(r->flags & BFS)) { + while (r->hist) { + h = r->hist; + r->hist = r->hist->prev; + free(h); + } } } closedir(dp); } + +void +recurselater(const char *path, void *data, struct recursor *r) +{ + struct pendingrecurse *elem = malloc(sizeof(*elem)); + if (!elem && !(r->flags & SILENT)) { + weprintf("malloc:"); + recurse_status = 1; + return; + } + elem->path = estrdup(path); + elem->data = data; + elem->depth = r->depth; + TAILQ_INSERT_TAIL(&r->pending, elem, entry); +} + +void +recursenow(struct recursor *r) +{ + struct pendingrecurse *elem; + char *path; + void *data; + struct history *h; + + while (!TAILQ_EMPTY(&r->pending)) { + elem = TAILQ_FIRST(&r->pending); + path = elem->path; + data = elem->data; + r->depth = elem->depth; + TAILQ_REMOVE(&r->pending, elem, entry); + free(elem); + recurse(path, data, r); + free(path); + } + + while (r->hist) { + h = r->hist; + r->hist = r->hist->prev; + free(h); + } +} -- 2.8.0Received on Mon Apr 04 2016 - 20:32:58 CEST
This archive was generated by hypermail 2.3.0 : Mon Apr 04 2016 - 20:36:16 CEST