Print this page
3047 grep support for -r would be useful
*** 22,33 ****
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
- #pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* grep - pattern matching program - combined grep, egrep, and fgrep.
* Based on MKS grep command, with XCU & Solaris mods.
*/
--- 22,31 ----
*** 34,43 ****
--- 32,43 ----
/*
* Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved.
*
*/
+ /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */
+
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <regex.h>
*** 49,61 ****
--- 49,64 ----
#include <locale.h>
#include <wchar.h>
#include <errno.h>
#include <unistd.h>
#include <wctype.h>
+ #include <ftw.h>
+ #include <sys/param.h>
#define BSIZE 512 /* Size of block for -b */
#define BUFSIZE 8192 /* Input buffer size */
+ #define MAX_DEPTH 1000 /* how deep to recurse */
#define M_CSETSIZE 256 /* singlebyte chars */
static int bmglen; /* length of BMG pattern */
static char *bmgpat; /* BMG pattern */
static int bmgtab[M_CSETSIZE]; /* BMG delta1 table */
*** 68,120 ****
} PATTERN;
static PATTERN *patterns;
static char errstr[128]; /* regerror string buffer */
static int regflags = 0; /* regcomp options */
static uchar_t fgrep = 0; /* Invoked as fgrep */
static uchar_t egrep = 0; /* Invoked as egrep */
static uchar_t nvflag = 1; /* Print matching lines */
static uchar_t cflag; /* Count of matches */
static uchar_t iflag; /* Case insensitve matching */
static uchar_t hflag; /* Supress printing of filename */
static uchar_t lflag; /* Print file names of matches */
static uchar_t nflag; /* Precede lines by line number */
static uchar_t bflag; /* Preccede matches by block number */
static uchar_t sflag; /* Suppress file error messages */
static uchar_t qflag; /* Suppress standard output */
static uchar_t wflag; /* Search for expression as a word */
static uchar_t xflag; /* Anchoring */
static uchar_t Eflag; /* Egrep or -E flag */
static uchar_t Fflag; /* Fgrep or -F flag */
static uchar_t outfn; /* Put out file name */
static char *cmdname;
static int use_wchar, use_bmg, mblocale;
static size_t outbuflen, prntbuflen;
static char *prntbuf;
static wchar_t *outline;
! static void addfile(char *fn);
static void addpattern(char *s);
static void fixpatterns(void);
static void usage(void);
! static int grep(int, char *);
static void bmgcomp(char *, int);
static char *bmgexec(char *, char *);
/*
* mainline for grep
*/
int
main(int argc, char **argv)
{
char *ap;
- int matched = 0;
int c;
int fflag = 0;
- int errors = 0;
int i, n_pattern = 0, n_file = 0;
char **pattern_list = NULL;
char **file_list = NULL;
(void) setlocale(LC_ALL, "");
--- 71,128 ----
} PATTERN;
static PATTERN *patterns;
static char errstr[128]; /* regerror string buffer */
static int regflags = 0; /* regcomp options */
+ static int matched = 0; /* return of the grep() */
+ static int errors = 0; /* count of errors */
static uchar_t fgrep = 0; /* Invoked as fgrep */
static uchar_t egrep = 0; /* Invoked as egrep */
static uchar_t nvflag = 1; /* Print matching lines */
static uchar_t cflag; /* Count of matches */
static uchar_t iflag; /* Case insensitve matching */
static uchar_t hflag; /* Supress printing of filename */
static uchar_t lflag; /* Print file names of matches */
static uchar_t nflag; /* Precede lines by line number */
+ static uchar_t rflag; /* Search directories recursively */
static uchar_t bflag; /* Preccede matches by block number */
static uchar_t sflag; /* Suppress file error messages */
static uchar_t qflag; /* Suppress standard output */
static uchar_t wflag; /* Search for expression as a word */
static uchar_t xflag; /* Anchoring */
static uchar_t Eflag; /* Egrep or -E flag */
static uchar_t Fflag; /* Fgrep or -F flag */
+ static uchar_t Rflag; /* Like rflag, but follow symlinks */
static uchar_t outfn; /* Put out file name */
static char *cmdname;
static int use_wchar, use_bmg, mblocale;
static size_t outbuflen, prntbuflen;
static char *prntbuf;
static wchar_t *outline;
! static void addfile(const char *fn);
static void addpattern(char *s);
static void fixpatterns(void);
static void usage(void);
! static int grep(int, const char *);
static void bmgcomp(char *, int);
static char *bmgexec(char *, char *);
+ static int recursive(const char *, const struct stat *, int, struct FTW *);
+ static void process_path(const char *);
+ static void process_file(const char *, int);
/*
* mainline for grep
*/
int
main(int argc, char **argv)
{
char *ap;
int c;
int fflag = 0;
int i, n_pattern = 0, n_file = 0;
char **pattern_list = NULL;
char **file_list = NULL;
(void) setlocale(LC_ALL, "");
*** 145,155 ****
if (*ap == 'f' || *ap == 'F') {
fgrep++;
}
}
! while ((c = getopt(argc, argv, "vwchilnbse:f:qxEFI")) != EOF) {
switch (c) {
case 'v': /* POSIX: negate matches */
nvflag = 0;
break;
--- 153,163 ----
if (*ap == 'f' || *ap == 'F') {
fgrep++;
}
}
! while ((c = getopt(argc, argv, "vwchilnrbse:f:qxEFIR")) != EOF) {
switch (c) {
case 'v': /* POSIX: negate matches */
nvflag = 0;
break;
*** 168,177 ****
--- 176,189 ----
case 'n': /* POSIX: Write line numbers */
nflag++;
break;
+ case 'r': /* Solaris: search recursively */
+ rflag++;
+ break;
+
case 'b': /* Solaris: Write file block numbers */
bflag++;
break;
case 's': /* POSIX: No error msgs for files */
*** 228,237 ****
--- 240,254 ----
case 'F': /* POSIX: strings, not RE's */
Fflag++;
break;
+ case 'R': /* Solaris: like rflag, but follow symlinks */
+ Rflag++;
+ rflag++;
+ break;
+
default:
usage();
}
}
/*
*** 332,358 ****
matched = grep(0, gettext("(standard input)"));
} else {
if (argc > 2 && hflag == 0)
outfn = 1; /* Print filename on match line */
for (argv++; *argv != NULL; argv++) {
! int fd;
!
! if ((fd = open(*argv, O_RDONLY)) == -1) {
! errors = 1;
! if (sflag)
! continue;
! (void) fprintf(stderr, gettext(
! "%s: can't open \"%s\"\n"),
! cmdname, *argv);
! continue;
}
- matched |= grep(fd, *argv);
- (void) close(fd);
- if (ferror(stdout))
- break;
}
- }
/*
* Return() here is used instead of exit
*/
(void) fflush(stdout);
--- 349,361 ----
matched = grep(0, gettext("(standard input)"));
} else {
if (argc > 2 && hflag == 0)
outfn = 1; /* Print filename on match line */
for (argv++; *argv != NULL; argv++) {
! process_path(*argv);
}
}
/*
* Return() here is used instead of exit
*/
(void) fflush(stdout);
*** 360,374 ****
if (errors)
return (2);
return (matched ? 0 : 1);
}
/*
* Add a file of strings to the pattern list.
*/
static void
! addfile(char *fn)
{
FILE *fp;
char *inbuf;
char *bufp;
size_t bufsiz, buflen, bufused;
--- 363,476 ----
if (errors)
return (2);
return (matched ? 0 : 1);
}
+ static void
+ process_path(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; /* Print filename */
+
+ /*
+ * 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)
+ (void) fprintf(stderr,
+ gettext("%s: can't open \"%s\"\n"),
+ cmdname, path);
+ errors = 1;
+ }
+ return;
+ }
+ }
+ process_file(path, 0);
+ }
+
/*
+ * Read and process all files in directory recursively.
+ */
+ 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) {
+ /* Report broken symlinks and unreadable files */
+ if (!sflag &&
+ (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
+ (void) fprintf(stderr,
+ gettext("%s: can't open \"%s\"\n"), cmdname, 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 */
+ process_file(name, ftw->base);
+ return (0);
+ }
+
+ /*
+ * Opens file and call grep function.
+ */
+ static void
+ process_file(const char *name, int base)
+ {
+ int fd;
+
+ if ((fd = open(name + base, O_RDONLY)) == -1) {
+ errors = 1;
+ if (!sflag) /* Silent mode */
+ (void) fprintf(stderr, gettext(
+ "%s: can't open \"%s\"\n"),
+ cmdname, name);
+ return;
+ }
+ matched |= grep(fd, name);
+ (void) close(fd);
+
+ if (ferror(stdout)) {
+ (void) fprintf(stderr, gettext(
+ "%s: error writing to stdout\n"),
+ cmdname);
+ (void) fflush(stdout);
+ exit(2);
+ }
+
+ }
+
+ /*
* Add a file of strings to the pattern list.
*/
static void
! addfile(const char *fn)
{
FILE *fp;
char *inbuf;
char *bufp;
size_t bufsiz, buflen, bufused;
*** 673,683 ****
* This is an order of magnitude faster.
* Otherwise we split the buffer into lines,
* and check for a match on each line.
*/
static int
! grep(int fd, char *fn)
{
PATTERN *pp;
off_t data_len; /* length of the data chunk */
off_t line_len; /* length of the current line */
off_t line_offset; /* current line's offset from the beginning */
--- 775,785 ----
* This is an order of magnitude faster.
* Otherwise we split the buffer into lines,
* and check for a match on each line.
*/
static int
! grep(int fd, const char *fn)
{
PATTERN *pp;
off_t data_len; /* length of the data chunk */
off_t line_len; /* length of the current line */
off_t line_offset; /* current line's offset from the beginning */
*** 738,752 ****
*/
count = read(fd, ptr + data_len, prntbuflen - data_len);
if (count < 0) {
/* read error */
if (cflag) {
! if (outfn) {
(void) fprintf(stdout,
"%s:", fn);
}
! if (!qflag) {
(void) fprintf(stdout, "%lld\n",
matches);
}
}
return (0);
--- 840,854 ----
*/
count = read(fd, ptr + data_len, prntbuflen - data_len);
if (count < 0) {
/* read error */
if (cflag) {
! if (outfn && !rflag) {
(void) fprintf(stdout,
"%s:", fn);
}
! if (!qflag && !rflag) {
(void) fprintf(stdout, "%lld\n",
matches);
}
}
return (0);
*** 1054,1094 ****
usage(void)
{
if (egrep || fgrep) {
(void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-bhinsvx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "
"[-f pattern_file]... [file...]\n"));
} else {
(void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-bhinsvwx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-bhinsvwx] [-e pattern_list]... "
"[-f pattern_file]... [file...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" -E [-c|-l|-q] [-bhinsvx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" -E [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "
"[-f pattern_file]... [file...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" -F [-c|-l|-q] [-bhinsvx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
gettext(" -F [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "
--- 1156,1199 ----
usage(void)
{
if (egrep || fgrep) {
(void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-r|-R] [-bhinsvx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-r|-R] [-bhinsvx] "
! "[-e pattern_list]... "
"[-f pattern_file]... [file...]\n"));
} else {
(void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-r|-R] [-bhinsvwx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" [-c|-l|-q] [-r|-R] [-bhinsvwx] "
! "[-e pattern_list]... "
"[-f pattern_file]... [file...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" -E [-c|-l|-q] [-r|-R] [-bhinsvx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" -E [-c|-l|-q] [-r|-R] [-bhinsvx] "
! "[-e pattern_list]... "
"[-f pattern_file]... [file...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
! gettext(" -F [-c|-l|-q] [-r|-R] [-bhinsvx] "
"pattern_list [file ...]\n"));
(void) fprintf(stderr, "\t%s", cmdname);
(void) fprintf(stderr,
gettext(" -F [-c|-l|-q] [-bhinsvx] [-e pattern_list]... "