Print this page
3047 grep support for -r would be useful
@@ -50,10 +50,13 @@
#include <regexpr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <ftw.h>
+#include <limits.h>
+#include <sys/param.h>
static const char *errstr[] = {
"Range endpoint too large.",
"Bad number.",
"``\\digit'' out of range.",
@@ -71,10 +74,11 @@
};
#define errmsg(msg, arg) (void) fprintf(stderr, gettext(msg), arg)
#define BLKSIZE 512
#define GBUFSIZ 8192
+#define MAX_DEPTH 1000
static int temp;
static long long lnum;
static char *linebuf;
static char *prntbuf = NULL;
@@ -81,10 +85,12 @@
static long fw_lPrntBufLen = 0;
static int nflag;
static int bflag;
static int lflag;
static int cflag;
+static int rflag;
+static int Rflag;
static int vflag;
static int sflag;
static int iflag;
static int wflag;
static int hflag;
@@ -91,17 +97,20 @@
static int qflag;
static int errflg;
static int nfile;
static long long tln;
static int nsucc;
+static int outfn = 0;
static int nlflag;
static char *ptr, *ptrend;
static char *expbuf;
-static void execute(char *);
+static void execute(const char *, int);
static void regerr(int);
-static int succeed(char *);
+static void prepare(const char *);
+static int recursive(const char *, const struct stat *, int, struct FTW *);
+static int succeed(const char *);
int
main(int argc, char **argv)
{
int c;
@@ -112,11 +121,11 @@
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
- while ((c = getopt(argc, argv, "hqblcnsviyw")) != -1)
+ while ((c = getopt(argc, argv, "hqblcnRrsviyw")) != -1)
switch (c) {
case 'h':
hflag++;
break;
case 'q': /* POSIX: quiet: status only */
@@ -129,10 +138,16 @@
cflag++;
break;
case 'n':
nflag++;
break;
+ case 'R':
+ Rflag++;
+ /* FALLTHROUGH */
+ case 'r':
+ rflag++;
+ break;
case 'b':
bflag++;
break;
case 's':
sflag++;
@@ -150,11 +165,12 @@
case '?':
errflg++;
}
if (errflg || (optind >= argc)) {
- errmsg("Usage: grep [-c|-l|-q] -hbnsviw pattern file . . .\n",
+ errmsg("Usage: grep [-c|-l|-q] [-r|-R] -hbnsviw "
+ "pattern file . . .\n",
(char *)NULL);
exit(2);
}
argv = &argv[optind];
@@ -188,21 +204,85 @@
expbuf = compile(*argv, (char *)0, (char *)0);
if (regerrno)
regerr(regerrno);
if (--argc == 0)
- execute(NULL);
+ execute(NULL, 0);
else
while (argc-- > 0)
- execute(*++argv);
+ prepare(*++argv);
return (nsucc == 2 ? 2 : (nsucc == 0 ? 1 : 0));
}
static void
-execute(char *file)
+prepare(const char *path)
{
+ struct stat st;
+ int walkflags = FTW_CHDIR;
+ char *buf = NULL;
+
+ if (rflag) {
+ if (stat(path, &st) != -1 &&
+ (st.st_mode & S_IFMT) == S_IFDIR) {
+ outfn = 1;
+
+ /*
+ * Add trailing slash if arg
+ * is directory, to resolve symlinks.
+ */
+ if (path[strlen(path) - 1] != '/') {
+ (void) asprintf(&buf, "%s/", path);
+ if (buf != NULL)
+ path = buf;
+ }
+
+ /*
+ * Search through subdirs if path is directory.
+ * Don't follow symlinks if Rflag is not set.
+ */
+ if (!Rflag)
+ walkflags |= FTW_PHYS;
+
+ if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) {
+ if (!sflag)
+ errmsg("grep: can't open %s\n", path);
+ nsucc = 2;
+ }
+ return;
+ }
+ }
+ execute(path, 0);
+}
+
+static int
+recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw)
+{
+ /*
+ * process files and follow symlinks if Rflag set.
+ */
+ if (info != FTW_F) {
+ if (!sflag &&
+ (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
+ /* report broken symlinks and unreadable files */
+ errmsg("grep: can't open %s\n", name);
+ }
+ return (0);
+ }
+
+ /* skip devices and pipes if Rflag is not set */
+ if (!Rflag && !S_ISREG(statp->st_mode))
+ return (0);
+
+ /* pass offset to relative name from FTW_CHDIR */
+ execute(name, ftw->base);
+ return (0);
+}
+
+static void
+execute(const char *file, int base)
+{
char *lbuf, *p;
long count;
long offset = 0;
char *next_ptr = NULL;
long next_count = 0;
@@ -219,11 +299,11 @@
}
}
if (file == NULL)
temp = 0;
- else if ((temp = open(file, O_RDONLY)) == -1) {
+ else if ((temp = open(file + base, O_RDONLY)) == -1) {
if (!sflag)
errmsg("grep: can't open %s\n", file);
nsucc = 2;
return;
}
@@ -233,10 +313,11 @@
(void) close(temp);
if (cflag && !qflag) {
if (nfile > 1 && !hflag && file)
(void) fprintf(stdout, "%s:", file);
+ if (!rflag)
(void) fprintf(stdout, "%lld\n", tln);
}
return;
}
@@ -327,18 +408,19 @@
offset = 0;
}
(void) close(temp);
if (cflag && !qflag) {
- if (nfile > 1 && !hflag && file)
+ if (!hflag && file && (nfile > 1 ||
+ (rflag && outfn)))
(void) fprintf(stdout, "%s:", file);
(void) fprintf(stdout, "%lld\n", tln);
}
}
static int
-succeed(char *f)
+succeed(const char *f)
{
int nchars;
nsucc = (nsucc == 2) ? 2 : 1;
if (f == NULL)
@@ -357,13 +439,14 @@
if (lflag) {
(void) fprintf(stdout, "%s\n", f);
return (1);
}
- if (nfile > 1 && !hflag)
+ if (!hflag && (nfile > 1 || (rflag && outfn))) {
/* print filename */
(void) fprintf(stdout, "%s:", f);
+ }
if (bflag)
/* print block number */
(void) fprintf(stdout, "%lld:", (offset_t)
((lseek(temp, (off_t)0, SEEK_CUR) - 1) / BLKSIZE));