4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
33 /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */
36 * Copyright 2013 Damian Bogel. All rights reserved.
40 * grep -- print lines matching (or not matching) a pattern
43 * 0 - ok, and some matches
44 * 1 - ok, but no matches
48 #include <sys/types.h>
61 #include <sys/param.h>
63 static const char *errstr
[] = {
64 "Range endpoint too large.",
66 "``\\digit'' out of range.",
67 "No remembered search string.",
70 "More than 2 numbers given in \\{ \\}.",
71 "} expected after \\.",
72 "First number exceeds second in \\{ \\}.",
74 "Regular expression overflow.",
75 "Illegal byte sequence.",
76 "Unknown regexp error code!!",
80 #define STDIN_FILENAME gettext("(standard input)")
82 #define errmsg(msg, arg) (void) fprintf(stderr, gettext(msg), arg)
85 #define MAX_DEPTH 1000
88 static long long lnum
;
90 static char *prntbuf
= NULL
;
91 static long fw_lPrntBufLen
= 0;
107 static long long tln
;
109 static int outfn
= 0;
111 static char *ptr
, *ptrend
;
114 static void execute(const char *, int);
115 static void regerr(int);
116 static void prepare(const char *);
117 static int recursive(const char *, const struct stat
*, int, struct FTW
*);
118 static int succeed(const char *);
121 main(int argc
, char **argv
)
127 (void) setlocale(LC_ALL
, "");
128 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
129 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
131 (void) textdomain(TEXT_DOMAIN
);
133 while ((c
= getopt(argc
, argv
, "hHqblcnRrsviyw")) != -1)
135 /* based on options order h or H is set as in GNU grep */
138 Hflag
= 0; /* h excludes H */
141 if (!lflag
) /* H is excluded by l */
143 hflag
= 0; /* H excludes h */
145 case 'q': /* POSIX: quiet: status only */
171 Hflag
= 0; /* l excludes H */
184 if (errflg
|| (optind
>= argc
)) {
185 errmsg("Usage: grep [-c|-l|-q] [-r|-R] -hHbnsviw "
186 "pattern file . . .\n",
191 argv
= &argv
[optind
];
195 if (strrchr(*argv
, '\n') != NULL
)
199 for (arg
= *argv
; *arg
!= NULL
; ++arg
)
200 *arg
= (char)tolower((int)((unsigned char)*arg
));
204 unsigned int wordlen
;
207 wordlen
= strlen(*argv
) + 5; /* '\\' '<' *argv '\\' '>' '\0' */
208 if ((wordbuf
= malloc(wordlen
)) == NULL
) {
209 errmsg("grep: Out of memory for word\n", (char *)NULL
);
213 (void) strcpy(wordbuf
, "\\<");
214 (void) strcat(wordbuf
, *argv
);
215 (void) strcat(wordbuf
, "\\>");
219 expbuf
= compile(*argv
, (char *)0, (char *)0);
229 return (nsucc
== 2 ? 2 : (nsucc
== 0 ? 1 : 0));
233 prepare(const char *path
)
236 int walkflags
= FTW_CHDIR
;
240 if (stat(path
, &st
) != -1 &&
241 (st
.st_mode
& S_IFMT
) == S_IFDIR
) {
245 * Add trailing slash if arg
246 * is directory, to resolve symlinks.
248 if (path
[strlen(path
) - 1] != '/') {
249 (void) asprintf(&buf
, "%s/", path
);
255 * Search through subdirs if path is directory.
256 * Don't follow symlinks if Rflag is not set.
259 walkflags
|= FTW_PHYS
;
261 if (nftw(path
, recursive
, MAX_DEPTH
, walkflags
) != 0) {
263 errmsg("grep: can't open %s\n", path
);
273 recursive(const char *name
, const struct stat
*statp
, int info
, struct FTW
*ftw
)
276 * process files and follow symlinks if Rflag set.
280 (info
== FTW_SLN
|| info
== FTW_DNR
|| info
== FTW_NS
)) {
281 /* report broken symlinks and unreadable files */
282 errmsg("grep: can't open %s\n", name
);
287 /* skip devices and pipes if Rflag is not set */
288 if (!Rflag
&& !S_ISREG(statp
->st_mode
))
291 /* pass offset to relative name from FTW_CHDIR */
292 execute(name
, ftw
->base
);
297 execute(const char *file
, int base
)
302 char *next_ptr
= NULL
;
307 if (prntbuf
== NULL
) {
308 fw_lPrntBufLen
= GBUFSIZ
+ 1;
309 if ((prntbuf
= malloc(fw_lPrntBufLen
)) == NULL
) {
310 exit(2); /* out of memory - BAIL */
312 if ((linebuf
= malloc(fw_lPrntBufLen
)) == NULL
) {
313 exit(2); /* out of memory - BAIL */
319 file
= STDIN_FILENAME
;
320 } else if ((temp
= open(file
+ base
, O_RDONLY
)) == -1) {
322 errmsg("grep: can't open %s\n", file
);
327 /* read in first block of bytes */
328 if ((count
= read(temp
, prntbuf
, GBUFSIZ
)) <= 0) {
331 if (cflag
&& !qflag
) {
332 if (Hflag
|| (nfile
> 1 && !hflag
))
333 (void) fprintf(stdout
, "%s:", file
);
335 (void) fprintf(stdout
, "%lld\n", tln
);
343 /* look for next newline */
344 if ((ptrend
= memchr(ptr
+ offset
, '\n', count
)) == NULL
) {
348 * shift unused data to the beginning of the buffer
351 (void) memmove(prntbuf
, ptr
, offset
);
356 * re-allocate a larger buffer if this one is full
358 if (offset
+ GBUFSIZ
> fw_lPrntBufLen
) {
360 * allocate a new buffer and preserve the
363 fw_lPrntBufLen
+= GBUFSIZ
;
364 if ((prntbuf
= realloc(prntbuf
,
365 fw_lPrntBufLen
)) == NULL
)
369 * set up a bigger linebuffer (this is only used
370 * for case insensitive operations). Contents do
371 * not have to be preserved.
374 if ((linebuf
= malloc(fw_lPrntBufLen
)) == NULL
)
380 p
= prntbuf
+ offset
;
381 if ((count
= read(temp
, p
, GBUFSIZ
)) > 0)
385 /* end of file already reached */
388 /* last line of file has no newline */
389 ptrend
= ptr
+ offset
;
392 next_ptr
= ptrend
+ 1;
393 next_count
= offset
+ count
- (next_ptr
- ptr
);
401 * Make a lower case copy of the record
404 for (lbuf
= linebuf
; p
< ptrend
; )
405 *lbuf
++ = (char)tolower((int)
406 (unsigned char)*p
++);
415 /* lflag only once */
416 if ((step(lbuf
, expbuf
) ^ vflag
) && succeed(file
) == 1)
428 if (cflag
&& !qflag
) {
429 if (Hflag
|| (!hflag
&& ((nfile
> 1) ||
431 (void) fprintf(stdout
, "%s:", file
);
432 (void) fprintf(stdout
, "%lld\n", tln
);
437 succeed(const char *f
)
440 nsucc
= (nsucc
== 2) ? 2 : 1;
443 /* no need to continue */
453 (void) fprintf(stdout
, "%s\n", f
);
457 if (Hflag
|| (!hflag
&& (nfile
> 1 || (rflag
&& outfn
)))) {
459 (void) fprintf(stdout
, "%s:", f
);
463 /* print block number */
464 (void) fprintf(stdout
, "%lld:", (offset_t
)
465 ((lseek(temp
, (off_t
)0, SEEK_CUR
) - 1) / BLKSIZE
));
468 /* print line number */
469 (void) fprintf(stdout
, "%lld:", lnum
);
472 /* newline at end of line */
474 nchars
= ptrend
- ptr
+ 1;
476 /* don't write sentinel \0 */
477 nchars
= ptrend
- ptr
;
480 (void) fwrite(ptr
, 1, nchars
, stdout
);
487 errmsg("grep: RE error %d: ", err
);
530 errmsg("%s\n", gettext(errstr
[err
]));