xref: /illumos-gate/usr/src/cmd/grep/grep.c (revision d2d52add)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*d2d52addSAlexander Pyhalov  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
2741599e9fSDamian Bogel /*
28*d2d52addSAlexander Pyhalov  * grep - pattern matching program - combined grep, egrep, and fgrep.
29*d2d52addSAlexander Pyhalov  *	Based on MKS grep command, with XCU & Solaris mods.
3041599e9fSDamian Bogel  */
3141599e9fSDamian Bogel 
327c478bd9Sstevel@tonic-gate /*
33*d2d52addSAlexander Pyhalov  * Copyright 1985, 1992 by Mortice Kern Systems Inc.  All rights reserved.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
37*d2d52addSAlexander Pyhalov /* Copyright 2017 Nexenta Systems, Inc.  All rights reserved. */
387c478bd9Sstevel@tonic-gate 
39*d2d52addSAlexander Pyhalov /*
40*d2d52addSAlexander Pyhalov  * Copyright 2013 Damian Bogel. All rights reserved.
41*d2d52addSAlexander Pyhalov  */
42*d2d52addSAlexander Pyhalov 
43*d2d52addSAlexander Pyhalov #include <string.h>
44*d2d52addSAlexander Pyhalov #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <ctype.h>
46*d2d52addSAlexander Pyhalov #include <stdarg.h>
47*d2d52addSAlexander Pyhalov #include <regex.h>
48*d2d52addSAlexander Pyhalov #include <limits.h>
49*d2d52addSAlexander Pyhalov #include <sys/types.h>
50*d2d52addSAlexander Pyhalov #include <sys/stat.h>
517c478bd9Sstevel@tonic-gate #include <fcntl.h>
527c478bd9Sstevel@tonic-gate #include <stdio.h>
53*d2d52addSAlexander Pyhalov #include <locale.h>
54*d2d52addSAlexander Pyhalov #include <wchar.h>
55*d2d52addSAlexander Pyhalov #include <errno.h>
567c478bd9Sstevel@tonic-gate #include <unistd.h>
57*d2d52addSAlexander Pyhalov #include <wctype.h>
58e52fb54bSAlexander Eremin #include <ftw.h>
59e52fb54bSAlexander Eremin #include <sys/param.h>
607c478bd9Sstevel@tonic-gate 
61*d2d52addSAlexander Pyhalov #define	STDIN_FILENAME gettext("(standard input)")
62*d2d52addSAlexander Pyhalov 
63*d2d52addSAlexander Pyhalov #define	BSIZE		512		/* Size of block for -b */
64*d2d52addSAlexander Pyhalov #define	BUFSIZE		8192		/* Input buffer size */
65*d2d52addSAlexander Pyhalov #define	MAX_DEPTH	1000		/* how deep to recurse */
66*d2d52addSAlexander Pyhalov 
67*d2d52addSAlexander Pyhalov #define	AFTER 	1			/* 'After' Context */
68*d2d52addSAlexander Pyhalov #define	BEFORE 	2			/* 'Before' Context */
69*d2d52addSAlexander Pyhalov #define	CONTEXT	(AFTER|BEFORE)		/* Full Context */
70*d2d52addSAlexander Pyhalov 
71*d2d52addSAlexander Pyhalov #define	M_CSETSIZE	256		/* singlebyte chars */
72*d2d52addSAlexander Pyhalov static int	bmglen;			/* length of BMG pattern */
73*d2d52addSAlexander Pyhalov static char	*bmgpat;		/* BMG pattern */
74*d2d52addSAlexander Pyhalov static int	bmgtab[M_CSETSIZE];	/* BMG delta1 table */
75*d2d52addSAlexander Pyhalov 
76*d2d52addSAlexander Pyhalov typedef	struct	_PATTERN	{
77*d2d52addSAlexander Pyhalov 	char	*pattern;		/* original pattern */
78*d2d52addSAlexander Pyhalov 	wchar_t	*wpattern;		/* wide, lowercased pattern */
79*d2d52addSAlexander Pyhalov 	struct	_PATTERN	*next;
80*d2d52addSAlexander Pyhalov 	regex_t	re;			/* compiled pattern */
81*d2d52addSAlexander Pyhalov } PATTERN;
82*d2d52addSAlexander Pyhalov 
83*d2d52addSAlexander Pyhalov static PATTERN	*patterns;
84*d2d52addSAlexander Pyhalov static char	errstr[128];		/* regerror string buffer */
85*d2d52addSAlexander Pyhalov static int	regflags = 0;		/* regcomp options */
86*d2d52addSAlexander Pyhalov static int	matched = 0;		/* return of the grep() */
87*d2d52addSAlexander Pyhalov static int	errors = 0;		/* count of errors */
88*d2d52addSAlexander Pyhalov static uchar_t	fgrep = 0;		/* Invoked as fgrep */
89*d2d52addSAlexander Pyhalov static uchar_t	egrep = 0;		/* Invoked as egrep */
90*d2d52addSAlexander Pyhalov static boolean_t	nvflag = B_TRUE;	/* Print matching lines */
91*d2d52addSAlexander Pyhalov static uchar_t	cflag;			/* Count of matches */
92*d2d52addSAlexander Pyhalov static uchar_t	iflag;			/* Case insensitve matching */
93*d2d52addSAlexander Pyhalov static uchar_t	Hflag;			/* Precede lines by file name */
94*d2d52addSAlexander Pyhalov static uchar_t	hflag;			/* Supress printing of filename */
95*d2d52addSAlexander Pyhalov static uchar_t	lflag;			/* Print file names of matches */
96*d2d52addSAlexander Pyhalov static uchar_t	nflag;			/* Precede lines by line number */
97*d2d52addSAlexander Pyhalov static uchar_t	rflag;			/* Search directories recursively */
98*d2d52addSAlexander Pyhalov static uchar_t	bflag;			/* Preccede matches by block number */
99*d2d52addSAlexander Pyhalov static uchar_t	sflag;			/* Suppress file error messages */
100*d2d52addSAlexander Pyhalov static uchar_t	qflag;			/* Suppress standard output */
101*d2d52addSAlexander Pyhalov static uchar_t	wflag;			/* Search for expression as a word */
102*d2d52addSAlexander Pyhalov static uchar_t	xflag;			/* Anchoring */
103*d2d52addSAlexander Pyhalov static uchar_t	Eflag;			/* Egrep or -E flag */
104*d2d52addSAlexander Pyhalov static uchar_t	Fflag;			/* Fgrep or -F flag */
105*d2d52addSAlexander Pyhalov static uchar_t	Rflag;			/* Like rflag, but follow symlinks */
106*d2d52addSAlexander Pyhalov static uchar_t	outfn;			/* Put out file name */
107*d2d52addSAlexander Pyhalov static uchar_t	conflag;		/* show context of matches */
108*d2d52addSAlexander Pyhalov static char	*cmdname;
109*d2d52addSAlexander Pyhalov 
110*d2d52addSAlexander Pyhalov static int	use_wchar, use_bmg, mblocale;
111*d2d52addSAlexander Pyhalov 
112*d2d52addSAlexander Pyhalov static size_t	outbuflen, prntbuflen, conbuflen;
113*d2d52addSAlexander Pyhalov static unsigned long 	conalen, conblen, conmatches;
114*d2d52addSAlexander Pyhalov static char	*prntbuf, *conbuf;
115*d2d52addSAlexander Pyhalov static wchar_t	*outline;
116*d2d52addSAlexander Pyhalov 
117*d2d52addSAlexander Pyhalov static void	addfile(const char *fn);
118*d2d52addSAlexander Pyhalov static void	addpattern(char *s);
119*d2d52addSAlexander Pyhalov static void	fixpatterns(void);
120*d2d52addSAlexander Pyhalov static void	usage(void);
121*d2d52addSAlexander Pyhalov static int	grep(int, const char *);
122*d2d52addSAlexander Pyhalov static void	bmgcomp(char *, int);
123*d2d52addSAlexander Pyhalov static char	*bmgexec(char *, char *);
124e52fb54bSAlexander Eremin static int	recursive(const char *, const struct stat *, int, struct FTW *);
125*d2d52addSAlexander Pyhalov static void	process_path(const char *);
126*d2d52addSAlexander Pyhalov static void	process_file(const char *, int);
1277c478bd9Sstevel@tonic-gate 
128*d2d52addSAlexander Pyhalov /*
129*d2d52addSAlexander Pyhalov  * mainline for grep
130*d2d52addSAlexander Pyhalov  */
1317c478bd9Sstevel@tonic-gate int
13255f91622Sceastha main(int argc, char **argv)
1337c478bd9Sstevel@tonic-gate {
134*d2d52addSAlexander Pyhalov 	char	*ap, *test;
1357c478bd9Sstevel@tonic-gate 	int	c;
136*d2d52addSAlexander Pyhalov 	int	fflag = 0;
137*d2d52addSAlexander Pyhalov 	int	i, n_pattern = 0, n_file = 0;
138*d2d52addSAlexander Pyhalov 	char	**pattern_list = NULL;
139*d2d52addSAlexander Pyhalov 	char	**file_list = NULL;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1427c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
143*d2d52addSAlexander Pyhalov #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
1447c478bd9Sstevel@tonic-gate #endif
1457c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1467c478bd9Sstevel@tonic-gate 
147*d2d52addSAlexander Pyhalov 	/*
148*d2d52addSAlexander Pyhalov 	 * true if this is running on the multibyte locale
149*d2d52addSAlexander Pyhalov 	 */
150*d2d52addSAlexander Pyhalov 	mblocale = (MB_CUR_MAX > 1);
151*d2d52addSAlexander Pyhalov 	/*
152*d2d52addSAlexander Pyhalov 	 * Skip leading slashes
153*d2d52addSAlexander Pyhalov 	 */
154*d2d52addSAlexander Pyhalov 	cmdname = argv[0];
155*d2d52addSAlexander Pyhalov 	if (ap = strrchr(cmdname, '/'))
156*d2d52addSAlexander Pyhalov 		cmdname = ap + 1;
157*d2d52addSAlexander Pyhalov 
158*d2d52addSAlexander Pyhalov 	ap = cmdname;
159*d2d52addSAlexander Pyhalov 	/*
160*d2d52addSAlexander Pyhalov 	 * Detect egrep/fgrep via command name, map to -E and -F options.
161*d2d52addSAlexander Pyhalov 	 */
162*d2d52addSAlexander Pyhalov 	if (*ap == 'e' || *ap == 'E') {
163*d2d52addSAlexander Pyhalov 		regflags |= REG_EXTENDED;
164*d2d52addSAlexander Pyhalov 		egrep++;
165*d2d52addSAlexander Pyhalov 	} else {
166*d2d52addSAlexander Pyhalov 		if (*ap == 'f' || *ap == 'F') {
167*d2d52addSAlexander Pyhalov 			fgrep++;
168*d2d52addSAlexander Pyhalov 		}
169*d2d52addSAlexander Pyhalov 	}
170*d2d52addSAlexander Pyhalov 
171*d2d52addSAlexander Pyhalov 	/* check for non-standard "-line-count" option */
172*d2d52addSAlexander Pyhalov 	for (i = 1; i < argc; i++) {
173*d2d52addSAlexander Pyhalov 		if (strcmp(argv[i], "--") == 0)
17441599e9fSDamian Bogel 			break;
175*d2d52addSAlexander Pyhalov 
176*d2d52addSAlexander Pyhalov 		/* isdigit() check prevents negative arguments */
177*d2d52addSAlexander Pyhalov 		if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
178*d2d52addSAlexander Pyhalov 			if (strlen(&argv[i][1]) !=
179*d2d52addSAlexander Pyhalov 			    strspn(&argv[i][1], "0123456789")) {
180*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr, gettext(
181*d2d52addSAlexander Pyhalov 				    "%s: Bad number flag\n"), argv[0]);
182*d2d52addSAlexander Pyhalov 				usage();
183*d2d52addSAlexander Pyhalov 			}
184*d2d52addSAlexander Pyhalov 
185*d2d52addSAlexander Pyhalov 			errno = 0;
186*d2d52addSAlexander Pyhalov 			conalen = conblen = strtoul(&argv[i][1], (char **)NULL,
187*d2d52addSAlexander Pyhalov 			    10);
188*d2d52addSAlexander Pyhalov 
189*d2d52addSAlexander Pyhalov 			if (errno != 0 || conalen >= ULONG_MAX) {
190*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr, gettext(
191*d2d52addSAlexander Pyhalov 				    "%s: Bad context argument\n"), argv[0]);
192*d2d52addSAlexander Pyhalov 			} else if (conalen)
193*d2d52addSAlexander Pyhalov 				conflag = CONTEXT;
194*d2d52addSAlexander Pyhalov 
195*d2d52addSAlexander Pyhalov 			while (i < argc) {
196*d2d52addSAlexander Pyhalov 				argv[i] = argv[i + 1];
197*d2d52addSAlexander Pyhalov 				i++;
198*d2d52addSAlexander Pyhalov 			}
199*d2d52addSAlexander Pyhalov 			argc--;
200*d2d52addSAlexander Pyhalov 		}
201*d2d52addSAlexander Pyhalov 	}
202*d2d52addSAlexander Pyhalov 
203*d2d52addSAlexander Pyhalov 	while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIRA:B:C:")) != EOF) {
204*d2d52addSAlexander Pyhalov 		unsigned long tval;
205*d2d52addSAlexander Pyhalov 		switch (c) {
206*d2d52addSAlexander Pyhalov 		case 'v':	/* POSIX: negate matches */
207*d2d52addSAlexander Pyhalov 			nvflag = B_FALSE;
2087c478bd9Sstevel@tonic-gate 			break;
209*d2d52addSAlexander Pyhalov 
210*d2d52addSAlexander Pyhalov 		case 'c':	/* POSIX: write count */
211*d2d52addSAlexander Pyhalov 			cflag++;
2123ed621bcSAlexander Eremin 			break;
213*d2d52addSAlexander Pyhalov 
214*d2d52addSAlexander Pyhalov 		case 'i':	/* POSIX: ignore case */
215*d2d52addSAlexander Pyhalov 			iflag++;
216*d2d52addSAlexander Pyhalov 			regflags |= REG_ICASE;
2177c478bd9Sstevel@tonic-gate 			break;
218*d2d52addSAlexander Pyhalov 
219*d2d52addSAlexander Pyhalov 		case 'l':	/* POSIX: Write filenames only */
220*d2d52addSAlexander Pyhalov 			lflag++;
2217c478bd9Sstevel@tonic-gate 			break;
222*d2d52addSAlexander Pyhalov 
223*d2d52addSAlexander Pyhalov 		case 'n':	/* POSIX: Write line numbers */
2247c478bd9Sstevel@tonic-gate 			nflag++;
2257c478bd9Sstevel@tonic-gate 			break;
226*d2d52addSAlexander Pyhalov 
227*d2d52addSAlexander Pyhalov 		case 'r':	/* Solaris: search recursively */
228e52fb54bSAlexander Eremin 			rflag++;
229e52fb54bSAlexander Eremin 			break;
230*d2d52addSAlexander Pyhalov 
231*d2d52addSAlexander Pyhalov 		case 'b':	/* Solaris: Write file block numbers */
2327c478bd9Sstevel@tonic-gate 			bflag++;
2337c478bd9Sstevel@tonic-gate 			break;
234*d2d52addSAlexander Pyhalov 
235*d2d52addSAlexander Pyhalov 		case 's':	/* POSIX: No error msgs for files */
2367c478bd9Sstevel@tonic-gate 			sflag++;
2377c478bd9Sstevel@tonic-gate 			break;
238*d2d52addSAlexander Pyhalov 
239*d2d52addSAlexander Pyhalov 		case 'e':	/* POSIX: pattern list */
240*d2d52addSAlexander Pyhalov 			n_pattern++;
241*d2d52addSAlexander Pyhalov 			pattern_list = realloc(pattern_list,
242*d2d52addSAlexander Pyhalov 			    sizeof (char *) * n_pattern);
243*d2d52addSAlexander Pyhalov 			if (pattern_list == NULL) {
244*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
245*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
246*d2d52addSAlexander Pyhalov 				    cmdname);
247*d2d52addSAlexander Pyhalov 				exit(2);
248*d2d52addSAlexander Pyhalov 			}
249*d2d52addSAlexander Pyhalov 			*(pattern_list + n_pattern - 1) = optarg;
2507c478bd9Sstevel@tonic-gate 			break;
251*d2d52addSAlexander Pyhalov 
252*d2d52addSAlexander Pyhalov 		case 'f':	/* POSIX: pattern file */
253*d2d52addSAlexander Pyhalov 			fflag = 1;
254*d2d52addSAlexander Pyhalov 			n_file++;
255*d2d52addSAlexander Pyhalov 			file_list = realloc(file_list,
256*d2d52addSAlexander Pyhalov 			    sizeof (char *) * n_file);
257*d2d52addSAlexander Pyhalov 			if (file_list == NULL) {
258*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
259*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
260*d2d52addSAlexander Pyhalov 				    cmdname);
261*d2d52addSAlexander Pyhalov 				exit(2);
262*d2d52addSAlexander Pyhalov 			}
263*d2d52addSAlexander Pyhalov 			*(file_list + n_file - 1) = optarg;
2647c478bd9Sstevel@tonic-gate 			break;
265*d2d52addSAlexander Pyhalov 
266*d2d52addSAlexander Pyhalov 		/* based on options order h or H is set as in GNU grep */
267*d2d52addSAlexander Pyhalov 		case 'h':	/* Solaris: supress printing of file name */
268*d2d52addSAlexander Pyhalov 			hflag = 1;
269*d2d52addSAlexander Pyhalov 			Hflag = 0;
270*d2d52addSAlexander Pyhalov 			break;
271*d2d52addSAlexander Pyhalov 		/* Solaris: precede every matching with file name */
272*d2d52addSAlexander Pyhalov 		case 'H':
273*d2d52addSAlexander Pyhalov 			Hflag = 1;
274*d2d52addSAlexander Pyhalov 			hflag = 0;
275*d2d52addSAlexander Pyhalov 			break;
276*d2d52addSAlexander Pyhalov 
277*d2d52addSAlexander Pyhalov 		case 'q':	/* POSIX: quiet: status only */
278*d2d52addSAlexander Pyhalov 			qflag++;
279*d2d52addSAlexander Pyhalov 			break;
280*d2d52addSAlexander Pyhalov 
281*d2d52addSAlexander Pyhalov 		case 'w':	/* Solaris: treat pattern as word */
2827c478bd9Sstevel@tonic-gate 			wflag++;
2837c478bd9Sstevel@tonic-gate 			break;
284*d2d52addSAlexander Pyhalov 
285*d2d52addSAlexander Pyhalov 		case 'x':	/* POSIX: full line matches */
286*d2d52addSAlexander Pyhalov 			xflag++;
287*d2d52addSAlexander Pyhalov 			regflags |= REG_ANCHOR;
288*d2d52addSAlexander Pyhalov 			break;
289*d2d52addSAlexander Pyhalov 
290*d2d52addSAlexander Pyhalov 		case 'E':	/* POSIX: Extended RE's */
291*d2d52addSAlexander Pyhalov 			regflags |= REG_EXTENDED;
292*d2d52addSAlexander Pyhalov 			Eflag++;
293*d2d52addSAlexander Pyhalov 			break;
294*d2d52addSAlexander Pyhalov 
295*d2d52addSAlexander Pyhalov 		case 'F':	/* POSIX: strings, not RE's */
296*d2d52addSAlexander Pyhalov 			Fflag++;
297*d2d52addSAlexander Pyhalov 			break;
298*d2d52addSAlexander Pyhalov 
299*d2d52addSAlexander Pyhalov 		case 'R':	/* Solaris: like rflag, but follow symlinks */
300*d2d52addSAlexander Pyhalov 			Rflag++;
301*d2d52addSAlexander Pyhalov 			rflag++;
302*d2d52addSAlexander Pyhalov 			break;
303*d2d52addSAlexander Pyhalov 
304*d2d52addSAlexander Pyhalov 		case 'A':	/* print N lines after each match */
305*d2d52addSAlexander Pyhalov 			errno = 0;
306*d2d52addSAlexander Pyhalov 			conalen = strtoul(optarg, &test, 10);
307*d2d52addSAlexander Pyhalov 			/* *test will be non-null if optarg is negative */
308*d2d52addSAlexander Pyhalov 			if (errno != 0 || *test != '\0' ||
309*d2d52addSAlexander Pyhalov 			    conalen >= ULONG_MAX) {
310*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr, gettext(
311*d2d52addSAlexander Pyhalov 				    "%s: Bad context argument: %s\n"),
312*d2d52addSAlexander Pyhalov 				    argv[0], optarg);
313*d2d52addSAlexander Pyhalov 				exit(2);
314*d2d52addSAlexander Pyhalov 			}
315*d2d52addSAlexander Pyhalov 			if (conalen)
316*d2d52addSAlexander Pyhalov 				conflag |= AFTER;
317*d2d52addSAlexander Pyhalov 			else
318*d2d52addSAlexander Pyhalov 				conflag &= ~AFTER;
319*d2d52addSAlexander Pyhalov 			break;
320*d2d52addSAlexander Pyhalov 		case 'B':	/* print N lines before each match */
321*d2d52addSAlexander Pyhalov 			errno = 0;
322*d2d52addSAlexander Pyhalov 			conblen = strtoul(optarg, &test, 10);
323*d2d52addSAlexander Pyhalov 			/* *test will be non-null if optarg is negative */
324*d2d52addSAlexander Pyhalov 			if (errno != 0 || *test != '\0' ||
325*d2d52addSAlexander Pyhalov 			    conblen >= ULONG_MAX) {
326*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr, gettext(
327*d2d52addSAlexander Pyhalov 				    "%s: Bad context argument: %s\n"),
328*d2d52addSAlexander Pyhalov 				    argv[0], optarg);
329*d2d52addSAlexander Pyhalov 				exit(2);
330*d2d52addSAlexander Pyhalov 			}
331*d2d52addSAlexander Pyhalov 			if (conblen)
332*d2d52addSAlexander Pyhalov 				conflag |= BEFORE;
333*d2d52addSAlexander Pyhalov 			else
334*d2d52addSAlexander Pyhalov 				conflag &= ~BEFORE;
335*d2d52addSAlexander Pyhalov 			break;
336*d2d52addSAlexander Pyhalov 		case 'C':	/* print N lines around each match */
337*d2d52addSAlexander Pyhalov 			errno = 0;
338*d2d52addSAlexander Pyhalov 			tval = strtoul(optarg, &test, 10);
339*d2d52addSAlexander Pyhalov 			/* *test will be non-null if optarg is negative */
340*d2d52addSAlexander Pyhalov 			if (errno != 0 || *test != '\0' || tval >= ULONG_MAX) {
341*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr, gettext(
342*d2d52addSAlexander Pyhalov 				    "%s: Bad context argument: %s\n"),
343*d2d52addSAlexander Pyhalov 				    argv[0], optarg);
344*d2d52addSAlexander Pyhalov 				exit(2);
345*d2d52addSAlexander Pyhalov 			}
346*d2d52addSAlexander Pyhalov 			if (tval) {
347*d2d52addSAlexander Pyhalov 				if ((conflag & BEFORE) == 0)
348*d2d52addSAlexander Pyhalov 					conblen = tval;
349*d2d52addSAlexander Pyhalov 				if ((conflag & AFTER) == 0)
350*d2d52addSAlexander Pyhalov 					conalen = tval;
351*d2d52addSAlexander Pyhalov 				conflag = CONTEXT;
352*d2d52addSAlexander Pyhalov 			}
353*d2d52addSAlexander Pyhalov 			break;
354*d2d52addSAlexander Pyhalov 
355*d2d52addSAlexander Pyhalov 		default:
356*d2d52addSAlexander Pyhalov 			usage();
3577c478bd9Sstevel@tonic-gate 		}
358*d2d52addSAlexander Pyhalov 	}
359*d2d52addSAlexander Pyhalov 	/*
360*d2d52addSAlexander Pyhalov 	 * If we're invoked as egrep or fgrep we need to do some checks
361*d2d52addSAlexander Pyhalov 	 */
3627c478bd9Sstevel@tonic-gate 
363*d2d52addSAlexander Pyhalov 	if (egrep || fgrep) {
364*d2d52addSAlexander Pyhalov 		/*
365*d2d52addSAlexander Pyhalov 		 * Use of -E or -F with egrep or fgrep is illegal
366*d2d52addSAlexander Pyhalov 		 */
367*d2d52addSAlexander Pyhalov 		if (Eflag || Fflag)
368*d2d52addSAlexander Pyhalov 			usage();
369*d2d52addSAlexander Pyhalov 		/*
370*d2d52addSAlexander Pyhalov 		 * Don't allow use of wflag with egrep / fgrep
371*d2d52addSAlexander Pyhalov 		 */
372*d2d52addSAlexander Pyhalov 		if (wflag)
373*d2d52addSAlexander Pyhalov 			usage();
374*d2d52addSAlexander Pyhalov 		/*
375*d2d52addSAlexander Pyhalov 		 * For Solaris the -s flag is equivalent to XCU -q
376*d2d52addSAlexander Pyhalov 		 */
377*d2d52addSAlexander Pyhalov 		if (sflag)
378*d2d52addSAlexander Pyhalov 			qflag++;
379*d2d52addSAlexander Pyhalov 		/*
380*d2d52addSAlexander Pyhalov 		 * done with above checks - set the appropriate flags
381*d2d52addSAlexander Pyhalov 		 */
382*d2d52addSAlexander Pyhalov 		if (egrep)
383*d2d52addSAlexander Pyhalov 			Eflag++;
384*d2d52addSAlexander Pyhalov 		else			/* Else fgrep */
385*d2d52addSAlexander Pyhalov 			Fflag++;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
388*d2d52addSAlexander Pyhalov 	if (wflag && (Eflag || Fflag)) {
389*d2d52addSAlexander Pyhalov 		/*
390*d2d52addSAlexander Pyhalov 		 * -w cannot be specified with grep -F
391*d2d52addSAlexander Pyhalov 		 */
392*d2d52addSAlexander Pyhalov 		usage();
393*d2d52addSAlexander Pyhalov 	}
3947c478bd9Sstevel@tonic-gate 
395*d2d52addSAlexander Pyhalov 	/*
396*d2d52addSAlexander Pyhalov 	 * -E and -F flags are mutually exclusive - check for this
397*d2d52addSAlexander Pyhalov 	 */
398*d2d52addSAlexander Pyhalov 	if (Eflag && Fflag)
399*d2d52addSAlexander Pyhalov 		usage();
4007c478bd9Sstevel@tonic-gate 
401*d2d52addSAlexander Pyhalov 	/*
402*d2d52addSAlexander Pyhalov 	 * -l overrides -H like in GNU grep
403*d2d52addSAlexander Pyhalov 	 */
404*d2d52addSAlexander Pyhalov 	if (lflag)
405*d2d52addSAlexander Pyhalov 		Hflag = 0;
406*d2d52addSAlexander Pyhalov 
407*d2d52addSAlexander Pyhalov 	/*
408*d2d52addSAlexander Pyhalov 	 * -c, -l and -q flags are mutually exclusive
409*d2d52addSAlexander Pyhalov 	 * We have -c override -l like in Solaris.
410*d2d52addSAlexander Pyhalov 	 * -q overrides -l & -c programmatically in grep() function.
411*d2d52addSAlexander Pyhalov 	 */
412*d2d52addSAlexander Pyhalov 	if (cflag && lflag)
413*d2d52addSAlexander Pyhalov 		lflag = 0;
4147c478bd9Sstevel@tonic-gate 
415*d2d52addSAlexander Pyhalov 	argv += optind - 1;
416*d2d52addSAlexander Pyhalov 	argc -= optind - 1;
4177c478bd9Sstevel@tonic-gate 
418*d2d52addSAlexander Pyhalov 	/*
419*d2d52addSAlexander Pyhalov 	 * Now handling -e and -f option
420*d2d52addSAlexander Pyhalov 	 */
421*d2d52addSAlexander Pyhalov 	if (pattern_list) {
422*d2d52addSAlexander Pyhalov 		for (i = 0; i < n_pattern; i++) {
423*d2d52addSAlexander Pyhalov 			addpattern(pattern_list[i]);
424*d2d52addSAlexander Pyhalov 		}
425*d2d52addSAlexander Pyhalov 		free(pattern_list);
426*d2d52addSAlexander Pyhalov 	}
427*d2d52addSAlexander Pyhalov 	if (file_list) {
428*d2d52addSAlexander Pyhalov 		for (i = 0; i < n_file; i++) {
429*d2d52addSAlexander Pyhalov 			addfile(file_list[i]);
4307c478bd9Sstevel@tonic-gate 		}
431*d2d52addSAlexander Pyhalov 		free(file_list);
432*d2d52addSAlexander Pyhalov 	}
4337c478bd9Sstevel@tonic-gate 
434*d2d52addSAlexander Pyhalov 	/*
435*d2d52addSAlexander Pyhalov 	 * No -e or -f?  Make sure there is one more arg, use it as the pattern.
436*d2d52addSAlexander Pyhalov 	 */
437*d2d52addSAlexander Pyhalov 	if (patterns == NULL && !fflag) {
438*d2d52addSAlexander Pyhalov 		if (argc < 2)
439*d2d52addSAlexander Pyhalov 			usage();
440*d2d52addSAlexander Pyhalov 		addpattern(argv[1]);
441*d2d52addSAlexander Pyhalov 		argc--;
442*d2d52addSAlexander Pyhalov 		argv++;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
445*d2d52addSAlexander Pyhalov 	/*
446*d2d52addSAlexander Pyhalov 	 * If -x flag is not specified or -i flag is specified
447*d2d52addSAlexander Pyhalov 	 * with fgrep in a multibyte locale, need to use
448*d2d52addSAlexander Pyhalov 	 * the wide character APIs.  Otherwise, byte-oriented
449*d2d52addSAlexander Pyhalov 	 * process will be done.
450*d2d52addSAlexander Pyhalov 	 */
451*d2d52addSAlexander Pyhalov 	use_wchar = Fflag && mblocale && (!xflag || iflag);
452*d2d52addSAlexander Pyhalov 
453*d2d52addSAlexander Pyhalov 	/*
454*d2d52addSAlexander Pyhalov 	 * Compile Patterns and also decide if BMG can be used
455*d2d52addSAlexander Pyhalov 	 */
456*d2d52addSAlexander Pyhalov 	fixpatterns();
457*d2d52addSAlexander Pyhalov 
458*d2d52addSAlexander Pyhalov 	/* Process all files: stdin, or rest of arg list */
459*d2d52addSAlexander Pyhalov 	if (argc < 2) {
460*d2d52addSAlexander Pyhalov 		matched = grep(0, STDIN_FILENAME);
461*d2d52addSAlexander Pyhalov 	} else {
462*d2d52addSAlexander Pyhalov 		if (Hflag || (argc > 2 && hflag == 0))
463*d2d52addSAlexander Pyhalov 			outfn = 1;	/* Print filename on match line */
464*d2d52addSAlexander Pyhalov 		for (argv++; *argv != NULL; argv++) {
465*d2d52addSAlexander Pyhalov 			process_path(*argv);
466*d2d52addSAlexander Pyhalov 		}
467*d2d52addSAlexander Pyhalov 	}
468*d2d52addSAlexander Pyhalov 	/*
469*d2d52addSAlexander Pyhalov 	 * Return() here is used instead of exit
470*d2d52addSAlexander Pyhalov 	 */
4717c478bd9Sstevel@tonic-gate 
472*d2d52addSAlexander Pyhalov 	(void) fflush(stdout);
4737c478bd9Sstevel@tonic-gate 
474*d2d52addSAlexander Pyhalov 	if (errors)
475*d2d52addSAlexander Pyhalov 		return (2);
476*d2d52addSAlexander Pyhalov 	return (matched ? 0 : 1);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate static void
480*d2d52addSAlexander Pyhalov process_path(const char *path)
481e52fb54bSAlexander Eremin {
482e52fb54bSAlexander Eremin 	struct	stat st;
483e52fb54bSAlexander Eremin 	int	walkflags = FTW_CHDIR;
484e52fb54bSAlexander Eremin 	char	*buf = NULL;
485e52fb54bSAlexander Eremin 
486e52fb54bSAlexander Eremin 	if (rflag) {
487e52fb54bSAlexander Eremin 		if (stat(path, &st) != -1 &&
488e52fb54bSAlexander Eremin 		    (st.st_mode & S_IFMT) == S_IFDIR) {
489*d2d52addSAlexander Pyhalov 			outfn = 1; /* Print filename */
490e52fb54bSAlexander Eremin 
491e52fb54bSAlexander Eremin 			/*
492e52fb54bSAlexander Eremin 			 * Add trailing slash if arg
493e52fb54bSAlexander Eremin 			 * is directory, to resolve symlinks.
494e52fb54bSAlexander Eremin 			 */
495e52fb54bSAlexander Eremin 			if (path[strlen(path) - 1] != '/') {
496e52fb54bSAlexander Eremin 				(void) asprintf(&buf, "%s/", path);
497e52fb54bSAlexander Eremin 				if (buf != NULL)
498e52fb54bSAlexander Eremin 					path = buf;
499e52fb54bSAlexander Eremin 			}
500e52fb54bSAlexander Eremin 
501e52fb54bSAlexander Eremin 			/*
502e52fb54bSAlexander Eremin 			 * Search through subdirs if path is directory.
503e52fb54bSAlexander Eremin 			 * Don't follow symlinks if Rflag is not set.
504e52fb54bSAlexander Eremin 			 */
505e52fb54bSAlexander Eremin 			if (!Rflag)
506e52fb54bSAlexander Eremin 				walkflags |= FTW_PHYS;
507e52fb54bSAlexander Eremin 
508e52fb54bSAlexander Eremin 			if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) {
509e52fb54bSAlexander Eremin 				if (!sflag)
510*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr,
511*d2d52addSAlexander Pyhalov 					    gettext("%s: can't open \"%s\"\n"),
512*d2d52addSAlexander Pyhalov 					    cmdname, path);
513*d2d52addSAlexander Pyhalov 				errors = 1;
514e52fb54bSAlexander Eremin 			}
515e52fb54bSAlexander Eremin 			return;
516e52fb54bSAlexander Eremin 		}
517e52fb54bSAlexander Eremin 	}
518*d2d52addSAlexander Pyhalov 	process_file(path, 0);
519e52fb54bSAlexander Eremin }
520e52fb54bSAlexander Eremin 
521*d2d52addSAlexander Pyhalov /*
522*d2d52addSAlexander Pyhalov  * Read and process all files in directory recursively.
523*d2d52addSAlexander Pyhalov  */
524e52fb54bSAlexander Eremin static int
525e52fb54bSAlexander Eremin recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw)
526e52fb54bSAlexander Eremin {
527e52fb54bSAlexander Eremin 	/*
528*d2d52addSAlexander Pyhalov 	 * Process files and follow symlinks if Rflag set.
529e52fb54bSAlexander Eremin 	 */
530e52fb54bSAlexander Eremin 	if (info != FTW_F) {
531*d2d52addSAlexander Pyhalov 		/* Report broken symlinks and unreadable files */
532e52fb54bSAlexander Eremin 		if (!sflag &&
533e52fb54bSAlexander Eremin 		    (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
534*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr,
535*d2d52addSAlexander Pyhalov 			    gettext("%s: can't open \"%s\"\n"), cmdname, name);
536e52fb54bSAlexander Eremin 		}
537e52fb54bSAlexander Eremin 		return (0);
538e52fb54bSAlexander Eremin 	}
539e52fb54bSAlexander Eremin 
540*d2d52addSAlexander Pyhalov 
541*d2d52addSAlexander Pyhalov 	/* Skip devices and pipes if Rflag is not set */
542e52fb54bSAlexander Eremin 	if (!Rflag && !S_ISREG(statp->st_mode))
543e52fb54bSAlexander Eremin 		return (0);
544*d2d52addSAlexander Pyhalov 	/* Pass offset to relative name from FTW_CHDIR */
545*d2d52addSAlexander Pyhalov 	process_file(name, ftw->base);
546e52fb54bSAlexander Eremin 	return (0);
547e52fb54bSAlexander Eremin }
548e52fb54bSAlexander Eremin 
549*d2d52addSAlexander Pyhalov /*
550*d2d52addSAlexander Pyhalov  * Opens file and call grep function.
551*d2d52addSAlexander Pyhalov  */
552e52fb54bSAlexander Eremin static void
553*d2d52addSAlexander Pyhalov process_file(const char *name, int base)
5547c478bd9Sstevel@tonic-gate {
555*d2d52addSAlexander Pyhalov 	int fd;
5567c478bd9Sstevel@tonic-gate 
557*d2d52addSAlexander Pyhalov 	if ((fd = open(name + base, O_RDONLY)) == -1) {
558*d2d52addSAlexander Pyhalov 		errors = 1;
559*d2d52addSAlexander Pyhalov 		if (!sflag) /* Silent mode */
560*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr, gettext(
561*d2d52addSAlexander Pyhalov 			    "%s: can't open \"%s\"\n"),
562*d2d52addSAlexander Pyhalov 			    cmdname, name);
563*d2d52addSAlexander Pyhalov 		return;
564*d2d52addSAlexander Pyhalov 	}
565*d2d52addSAlexander Pyhalov 	matched |= grep(fd, name);
566*d2d52addSAlexander Pyhalov 	(void) close(fd);
5677c478bd9Sstevel@tonic-gate 
568*d2d52addSAlexander Pyhalov 	if (ferror(stdout)) {
569*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, gettext(
570*d2d52addSAlexander Pyhalov 		    "%s: error writing to stdout\n"),
571*d2d52addSAlexander Pyhalov 		    cmdname);
572*d2d52addSAlexander Pyhalov 		(void) fflush(stdout);
573*d2d52addSAlexander Pyhalov 		exit(2);
574*d2d52addSAlexander Pyhalov 	}
575*d2d52addSAlexander Pyhalov 
576*d2d52addSAlexander Pyhalov }
577*d2d52addSAlexander Pyhalov 
578*d2d52addSAlexander Pyhalov /*
579*d2d52addSAlexander Pyhalov  * Add a file of strings to the pattern list.
580*d2d52addSAlexander Pyhalov  */
581*d2d52addSAlexander Pyhalov static void
582*d2d52addSAlexander Pyhalov addfile(const char *fn)
583*d2d52addSAlexander Pyhalov {
584*d2d52addSAlexander Pyhalov 	FILE	*fp;
585*d2d52addSAlexander Pyhalov 	char	*inbuf;
586*d2d52addSAlexander Pyhalov 	char	*bufp;
587*d2d52addSAlexander Pyhalov 	size_t	bufsiz, buflen, bufused;
588*d2d52addSAlexander Pyhalov 
589*d2d52addSAlexander Pyhalov 	/*
590*d2d52addSAlexander Pyhalov 	 * Open the pattern file
591*d2d52addSAlexander Pyhalov 	 */
592*d2d52addSAlexander Pyhalov 	if ((fp = fopen(fn, "r")) == NULL) {
593*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, gettext("%s: can't open \"%s\"\n"),
594*d2d52addSAlexander Pyhalov 		    cmdname, fn);
595*d2d52addSAlexander Pyhalov 		exit(2);
596*d2d52addSAlexander Pyhalov 	}
597*d2d52addSAlexander Pyhalov 	bufsiz = BUFSIZE;
598*d2d52addSAlexander Pyhalov 	if ((inbuf = malloc(bufsiz)) == NULL) {
599*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
600*d2d52addSAlexander Pyhalov 		    gettext("%s: out of memory\n"), cmdname);
601*d2d52addSAlexander Pyhalov 		exit(2);
602*d2d52addSAlexander Pyhalov 	}
603*d2d52addSAlexander Pyhalov 	bufp = inbuf;
604*d2d52addSAlexander Pyhalov 	bufused = 0;
605*d2d52addSAlexander Pyhalov 	/*
606*d2d52addSAlexander Pyhalov 	 * Read in the file, reallocing as we need more memory
607*d2d52addSAlexander Pyhalov 	 */
608*d2d52addSAlexander Pyhalov 	while (fgets(bufp, bufsiz - bufused, fp) != NULL) {
609*d2d52addSAlexander Pyhalov 		buflen = strlen(bufp);
610*d2d52addSAlexander Pyhalov 		bufused += buflen;
611*d2d52addSAlexander Pyhalov 		if (bufused + 1 == bufsiz && bufp[buflen - 1] != '\n') {
612*d2d52addSAlexander Pyhalov 			/*
613*d2d52addSAlexander Pyhalov 			 * if this line does not fit to the buffer,
614*d2d52addSAlexander Pyhalov 			 * realloc larger buffer
615*d2d52addSAlexander Pyhalov 			 */
616*d2d52addSAlexander Pyhalov 			bufsiz += BUFSIZE;
617*d2d52addSAlexander Pyhalov 			if ((inbuf = realloc(inbuf, bufsiz)) == NULL) {
618*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
619*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
620*d2d52addSAlexander Pyhalov 				    cmdname);
621*d2d52addSAlexander Pyhalov 				exit(2);
622*d2d52addSAlexander Pyhalov 			}
623*d2d52addSAlexander Pyhalov 			bufp = inbuf + bufused;
624*d2d52addSAlexander Pyhalov 			continue;
6257c478bd9Sstevel@tonic-gate 		}
626*d2d52addSAlexander Pyhalov 		if (bufp[buflen - 1] == '\n') {
627*d2d52addSAlexander Pyhalov 			bufp[--buflen] = '\0';
6287c478bd9Sstevel@tonic-gate 		}
629*d2d52addSAlexander Pyhalov 		addpattern(inbuf);
630*d2d52addSAlexander Pyhalov 
631*d2d52addSAlexander Pyhalov 		bufp = inbuf;
632*d2d52addSAlexander Pyhalov 		bufused = 0;
6337c478bd9Sstevel@tonic-gate 	}
634*d2d52addSAlexander Pyhalov 	free(inbuf);
635*d2d52addSAlexander Pyhalov 	free(prntbuf);
636*d2d52addSAlexander Pyhalov 	free(conbuf);
637*d2d52addSAlexander Pyhalov 	(void) fclose(fp);
638*d2d52addSAlexander Pyhalov }
6397c478bd9Sstevel@tonic-gate 
640*d2d52addSAlexander Pyhalov /*
641*d2d52addSAlexander Pyhalov  * Add a string to the pattern list.
642*d2d52addSAlexander Pyhalov  */
643*d2d52addSAlexander Pyhalov static void
644*d2d52addSAlexander Pyhalov addpattern(char *s)
645*d2d52addSAlexander Pyhalov {
646*d2d52addSAlexander Pyhalov 	PATTERN	*pp;
647*d2d52addSAlexander Pyhalov 	char	*wordbuf;
648*d2d52addSAlexander Pyhalov 	char	*np;
649*d2d52addSAlexander Pyhalov 
650*d2d52addSAlexander Pyhalov 	for (; ; ) {
651*d2d52addSAlexander Pyhalov 		np = strchr(s, '\n');
652*d2d52addSAlexander Pyhalov 		if (np != NULL)
653*d2d52addSAlexander Pyhalov 			*np = '\0';
654*d2d52addSAlexander Pyhalov 		if ((pp = malloc(sizeof (PATTERN))) == NULL) {
655*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr, gettext(
656*d2d52addSAlexander Pyhalov 			    "%s: out of memory\n"),
657*d2d52addSAlexander Pyhalov 			    cmdname);
658*d2d52addSAlexander Pyhalov 			exit(2);
659*d2d52addSAlexander Pyhalov 		}
660*d2d52addSAlexander Pyhalov 		if (wflag) {
661*d2d52addSAlexander Pyhalov 			/*
662*d2d52addSAlexander Pyhalov 			 * Solaris wflag support: Add '<' '>' to pattern to
663*d2d52addSAlexander Pyhalov 			 * select it as a word. Doesn't make sense with -F
664*d2d52addSAlexander Pyhalov 			 * but we're Libertarian.
665*d2d52addSAlexander Pyhalov 			 */
666*d2d52addSAlexander Pyhalov 			size_t	slen, wordlen;
667*d2d52addSAlexander Pyhalov 
668*d2d52addSAlexander Pyhalov 			slen = strlen(s);
669*d2d52addSAlexander Pyhalov 			wordlen = slen + 5; /* '\\' '<' s '\\' '>' '\0' */
670*d2d52addSAlexander Pyhalov 			if ((wordbuf = malloc(wordlen)) == NULL) {
671*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
672*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
673*d2d52addSAlexander Pyhalov 				    cmdname);
674*d2d52addSAlexander Pyhalov 				exit(2);
675*d2d52addSAlexander Pyhalov 			}
676*d2d52addSAlexander Pyhalov 			(void) strcpy(wordbuf, "\\<");
677*d2d52addSAlexander Pyhalov 			(void) strcpy(wordbuf + 2, s);
678*d2d52addSAlexander Pyhalov 			(void) strcpy(wordbuf + 2 + slen, "\\>");
679*d2d52addSAlexander Pyhalov 		} else {
680*d2d52addSAlexander Pyhalov 			if ((wordbuf = strdup(s)) == NULL) {
681*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
682*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
683*d2d52addSAlexander Pyhalov 				    cmdname);
684*d2d52addSAlexander Pyhalov 				exit(2);
685*d2d52addSAlexander Pyhalov 			}
686*d2d52addSAlexander Pyhalov 		}
687*d2d52addSAlexander Pyhalov 		pp->pattern = wordbuf;
688*d2d52addSAlexander Pyhalov 		pp->next = patterns;
689*d2d52addSAlexander Pyhalov 		patterns = pp;
690*d2d52addSAlexander Pyhalov 		if (np == NULL)
691*d2d52addSAlexander Pyhalov 			break;
692*d2d52addSAlexander Pyhalov 		s = np + 1;
6937c478bd9Sstevel@tonic-gate 	}
694*d2d52addSAlexander Pyhalov }
695*d2d52addSAlexander Pyhalov 
696*d2d52addSAlexander Pyhalov /*
697*d2d52addSAlexander Pyhalov  * Fix patterns.
698*d2d52addSAlexander Pyhalov  * Must do after all arguments read, in case later -i option.
699*d2d52addSAlexander Pyhalov  */
700*d2d52addSAlexander Pyhalov static void
701*d2d52addSAlexander Pyhalov fixpatterns(void)
702*d2d52addSAlexander Pyhalov {
703*d2d52addSAlexander Pyhalov 	PATTERN	*pp;
704*d2d52addSAlexander Pyhalov 	int	rv, fix_pattern, npatterns;
7057c478bd9Sstevel@tonic-gate 
706*d2d52addSAlexander Pyhalov 	/*
707*d2d52addSAlexander Pyhalov 	 * As REG_ANCHOR flag is not supported in the current Solaris,
708*d2d52addSAlexander Pyhalov 	 * need to fix the specified pattern if -x is specified with
709*d2d52addSAlexander Pyhalov 	 * grep or egrep
710*d2d52addSAlexander Pyhalov 	 */
711*d2d52addSAlexander Pyhalov 	fix_pattern = !Fflag && xflag;
712*d2d52addSAlexander Pyhalov 
713*d2d52addSAlexander Pyhalov 	for (npatterns = 0, pp = patterns; pp != NULL; pp = pp->next) {
714*d2d52addSAlexander Pyhalov 		npatterns++;
715*d2d52addSAlexander Pyhalov 		if (fix_pattern) {
716*d2d52addSAlexander Pyhalov 			char	*cp, *cq;
717*d2d52addSAlexander Pyhalov 			size_t	plen, nplen;
7187c478bd9Sstevel@tonic-gate 
719*d2d52addSAlexander Pyhalov 			plen = strlen(pp->pattern);
720*d2d52addSAlexander Pyhalov 			/* '^' pattern '$' */
721*d2d52addSAlexander Pyhalov 			nplen = 1 + plen + 1 + 1;
722*d2d52addSAlexander Pyhalov 			if ((cp = malloc(nplen)) == NULL) {
723*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
724*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
725*d2d52addSAlexander Pyhalov 				    cmdname);
726*d2d52addSAlexander Pyhalov 				exit(2);
727*d2d52addSAlexander Pyhalov 			}
728*d2d52addSAlexander Pyhalov 			cq = cp;
729*d2d52addSAlexander Pyhalov 			*cq++ = '^';
730*d2d52addSAlexander Pyhalov 			cq = strcpy(cq, pp->pattern) + plen;
731*d2d52addSAlexander Pyhalov 			*cq++ = '$';
732*d2d52addSAlexander Pyhalov 			*cq = '\0';
733*d2d52addSAlexander Pyhalov 			free(pp->pattern);
734*d2d52addSAlexander Pyhalov 			pp->pattern = cp;
7357c478bd9Sstevel@tonic-gate 		}
736*d2d52addSAlexander Pyhalov 
737*d2d52addSAlexander Pyhalov 		if (Fflag) {
738*d2d52addSAlexander Pyhalov 			if (use_wchar) {
739*d2d52addSAlexander Pyhalov 				/*
740*d2d52addSAlexander Pyhalov 				 * Fflag && mblocale && iflag
741*d2d52addSAlexander Pyhalov 				 * Fflag && mblocale && !xflag
742*d2d52addSAlexander Pyhalov 				 */
743*d2d52addSAlexander Pyhalov 				size_t	n;
744*d2d52addSAlexander Pyhalov 				n = strlen(pp->pattern) + 1;
745*d2d52addSAlexander Pyhalov 				if ((pp->wpattern =
746*d2d52addSAlexander Pyhalov 				    malloc(sizeof (wchar_t) * n)) == NULL) {
747*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr,
748*d2d52addSAlexander Pyhalov 					    gettext("%s: out of memory\n"),
749*d2d52addSAlexander Pyhalov 					    cmdname);
750*d2d52addSAlexander Pyhalov 					exit(2);
751*d2d52addSAlexander Pyhalov 				}
752*d2d52addSAlexander Pyhalov 				if (mbstowcs(pp->wpattern, pp->pattern, n) ==
753*d2d52addSAlexander Pyhalov 				    (size_t)-1) {
754*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr,
755*d2d52addSAlexander Pyhalov 					    gettext("%s: failed to convert "
756*d2d52addSAlexander Pyhalov 					    "\"%s\" to wide-characters\n"),
757*d2d52addSAlexander Pyhalov 					    cmdname, pp->pattern);
758*d2d52addSAlexander Pyhalov 					exit(2);
759*d2d52addSAlexander Pyhalov 				}
760*d2d52addSAlexander Pyhalov 				if (iflag) {
761*d2d52addSAlexander Pyhalov 					wchar_t	*wp;
762*d2d52addSAlexander Pyhalov 					for (wp = pp->wpattern; *wp != L'\0';
763*d2d52addSAlexander Pyhalov 					    wp++) {
764*d2d52addSAlexander Pyhalov 						*wp = towlower((wint_t)*wp);
765*d2d52addSAlexander Pyhalov 					}
766*d2d52addSAlexander Pyhalov 				}
767*d2d52addSAlexander Pyhalov 				free(pp->pattern);
768*d2d52addSAlexander Pyhalov 			} else {
769*d2d52addSAlexander Pyhalov 				/*
770*d2d52addSAlexander Pyhalov 				 * Fflag && mblocale && !iflag
771*d2d52addSAlexander Pyhalov 				 * Fflag && !mblocale && iflag
772*d2d52addSAlexander Pyhalov 				 * Fflag && !mblocale && !iflag
773*d2d52addSAlexander Pyhalov 				 */
774*d2d52addSAlexander Pyhalov 				if (iflag) {
775*d2d52addSAlexander Pyhalov 					unsigned char	*cp;
776*d2d52addSAlexander Pyhalov 					for (cp = (unsigned char *)pp->pattern;
777*d2d52addSAlexander Pyhalov 					    *cp != '\0'; cp++) {
778*d2d52addSAlexander Pyhalov 						*cp = tolower(*cp);
779*d2d52addSAlexander Pyhalov 					}
780*d2d52addSAlexander Pyhalov 				}
781*d2d52addSAlexander Pyhalov 			}
782*d2d52addSAlexander Pyhalov 			/*
783*d2d52addSAlexander Pyhalov 			 * fgrep: No regular expressions.
784*d2d52addSAlexander Pyhalov 			 */
785*d2d52addSAlexander Pyhalov 			continue;
786*d2d52addSAlexander Pyhalov 		}
787*d2d52addSAlexander Pyhalov 
788*d2d52addSAlexander Pyhalov 		/*
789*d2d52addSAlexander Pyhalov 		 * For non-fgrep, compile the regular expression,
790*d2d52addSAlexander Pyhalov 		 * give an informative error message, and exit if
791*d2d52addSAlexander Pyhalov 		 * it didn't compile.
792*d2d52addSAlexander Pyhalov 		 */
793*d2d52addSAlexander Pyhalov 		if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) {
794*d2d52addSAlexander Pyhalov 			(void) regerror(rv, &pp->re, errstr, sizeof (errstr));
795*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr,
796*d2d52addSAlexander Pyhalov 			    gettext("%s: RE error in %s: %s\n"),
797*d2d52addSAlexander Pyhalov 			    cmdname, pp->pattern, errstr);
798*d2d52addSAlexander Pyhalov 			exit(2);
799*d2d52addSAlexander Pyhalov 		}
800*d2d52addSAlexander Pyhalov 		free(pp->pattern);
801*d2d52addSAlexander Pyhalov 	}
802*d2d52addSAlexander Pyhalov 
803*d2d52addSAlexander Pyhalov 	/*
804*d2d52addSAlexander Pyhalov 	 * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
805*d2d52addSAlexander Pyhalov 	 * Use the Boyer-Moore-Gosper algorithm if:
806*d2d52addSAlexander Pyhalov 	 * - fgrep			(Fflag)
807*d2d52addSAlexander Pyhalov 	 * - singlebyte locale		(!mblocale)
808*d2d52addSAlexander Pyhalov 	 * - no ignoring case		(!iflag)
809*d2d52addSAlexander Pyhalov 	 * - no printing line numbers	(!nflag)
810*d2d52addSAlexander Pyhalov 	 * - no negating the output	(nvflag)
811*d2d52addSAlexander Pyhalov 	 * - only one pattern		(npatterns == 1)
812*d2d52addSAlexander Pyhalov 	 * - non zero length pattern	(strlen(patterns->pattern) != 0)
813*d2d52addSAlexander Pyhalov 	 * - no context required	(conflag == 0)
814*d2d52addSAlexander Pyhalov 	 *
815*d2d52addSAlexander Pyhalov 	 * It's guaranteed patterns->pattern is still alive
816*d2d52addSAlexander Pyhalov 	 * when Fflag && !mblocale.
817*d2d52addSAlexander Pyhalov 	 */
818*d2d52addSAlexander Pyhalov 	use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag &&
819*d2d52addSAlexander Pyhalov 	    (npatterns == 1) && (strlen(patterns->pattern) != 0) &&
820*d2d52addSAlexander Pyhalov 	    conflag == 0;
821*d2d52addSAlexander Pyhalov }
822*d2d52addSAlexander Pyhalov 
823*d2d52addSAlexander Pyhalov /*
824*d2d52addSAlexander Pyhalov  * Search a newline from the beginning of the string
825*d2d52addSAlexander Pyhalov  */
826*d2d52addSAlexander Pyhalov static char *
827*d2d52addSAlexander Pyhalov find_nl(const char *ptr, size_t len)
828*d2d52addSAlexander Pyhalov {
829*d2d52addSAlexander Pyhalov 	while (len-- != 0) {
830*d2d52addSAlexander Pyhalov 		if (*ptr++ == '\n') {
831*d2d52addSAlexander Pyhalov 			return ((char *)--ptr);
832*d2d52addSAlexander Pyhalov 		}
833*d2d52addSAlexander Pyhalov 	}
834*d2d52addSAlexander Pyhalov 	return (NULL);
835*d2d52addSAlexander Pyhalov }
836*d2d52addSAlexander Pyhalov 
837*d2d52addSAlexander Pyhalov /*
838*d2d52addSAlexander Pyhalov  * Search a newline from the end of the string
839*d2d52addSAlexander Pyhalov  */
840*d2d52addSAlexander Pyhalov static char *
841*d2d52addSAlexander Pyhalov rfind_nl(const char *ptr, size_t len)
842*d2d52addSAlexander Pyhalov {
843*d2d52addSAlexander Pyhalov 	const char	*uptr = ptr + len;
844*d2d52addSAlexander Pyhalov 	while (len--) {
845*d2d52addSAlexander Pyhalov 		if (*--uptr == '\n') {
846*d2d52addSAlexander Pyhalov 			return ((char *)uptr);
847*d2d52addSAlexander Pyhalov 		}
848*d2d52addSAlexander Pyhalov 	}
849*d2d52addSAlexander Pyhalov 	return (NULL);
850*d2d52addSAlexander Pyhalov }
851*d2d52addSAlexander Pyhalov 
852*d2d52addSAlexander Pyhalov /*
853*d2d52addSAlexander Pyhalov  * Duplicate the specified string converting each character
854*d2d52addSAlexander Pyhalov  * into a lower case.
855*d2d52addSAlexander Pyhalov  */
856*d2d52addSAlexander Pyhalov static char *
857*d2d52addSAlexander Pyhalov istrdup(const char *s1)
858*d2d52addSAlexander Pyhalov {
859*d2d52addSAlexander Pyhalov 	static size_t	ibuflen = 0;
860*d2d52addSAlexander Pyhalov 	static char	*ibuf = NULL;
861*d2d52addSAlexander Pyhalov 	size_t	slen;
862*d2d52addSAlexander Pyhalov 	char	*p;
863*d2d52addSAlexander Pyhalov 
864*d2d52addSAlexander Pyhalov 	slen = strlen(s1);
865*d2d52addSAlexander Pyhalov 	if (slen >= ibuflen) {
866*d2d52addSAlexander Pyhalov 		/* ibuf does not fit to s1 */
867*d2d52addSAlexander Pyhalov 		ibuflen = slen + 1;
868*d2d52addSAlexander Pyhalov 		ibuf = realloc(ibuf, ibuflen);
869*d2d52addSAlexander Pyhalov 		if (ibuf == NULL) {
870*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr,
871*d2d52addSAlexander Pyhalov 			    gettext("%s: out of memory\n"), cmdname);
872*d2d52addSAlexander Pyhalov 			exit(2);
873*d2d52addSAlexander Pyhalov 		}
874*d2d52addSAlexander Pyhalov 	}
875*d2d52addSAlexander Pyhalov 	p = ibuf;
876*d2d52addSAlexander Pyhalov 	do {
877*d2d52addSAlexander Pyhalov 		*p++ = tolower(*s1);
878*d2d52addSAlexander Pyhalov 	} while (*s1++ != '\0');
879*d2d52addSAlexander Pyhalov 	return (ibuf);
880*d2d52addSAlexander Pyhalov }
881*d2d52addSAlexander Pyhalov 
882*d2d52addSAlexander Pyhalov /*
883*d2d52addSAlexander Pyhalov  * Do grep on a single file.
884*d2d52addSAlexander Pyhalov  * Return true in any lines matched.
885*d2d52addSAlexander Pyhalov  *
886*d2d52addSAlexander Pyhalov  * We have two strategies:
887*d2d52addSAlexander Pyhalov  * The fast one is used when we have a single pattern with
888*d2d52addSAlexander Pyhalov  * a string known to occur in the pattern. We can then
889*d2d52addSAlexander Pyhalov  * do a BMG match on the whole buffer.
890*d2d52addSAlexander Pyhalov  * This is an order of magnitude faster.
891*d2d52addSAlexander Pyhalov  * Otherwise we split the buffer into lines,
892*d2d52addSAlexander Pyhalov  * and check for a match on each line.
893*d2d52addSAlexander Pyhalov  */
894*d2d52addSAlexander Pyhalov static int
895*d2d52addSAlexander Pyhalov grep(int fd, const char *fn)
896*d2d52addSAlexander Pyhalov {
897*d2d52addSAlexander Pyhalov 	PATTERN *pp;
898*d2d52addSAlexander Pyhalov 	off_t	data_len;	/* length of the data chunk */
899*d2d52addSAlexander Pyhalov 	off_t	line_len;	/* length of the current line */
900*d2d52addSAlexander Pyhalov 	off_t	line_offset;	/* current line's offset from the beginning */
901*d2d52addSAlexander Pyhalov 	off_t	blkoffset;	/* line_offset but context-compatible */
902*d2d52addSAlexander Pyhalov 	long long	lineno, linenum;
903*d2d52addSAlexander Pyhalov 	long long	matches = 0;	/* Number of matching lines */
904*d2d52addSAlexander Pyhalov 	long long	conacnt = 0, conbcnt = 0; 	/* context line count */
905*d2d52addSAlexander Pyhalov 	int	newlinep;	/* 0 if the last line of file has no newline */
906*d2d52addSAlexander Pyhalov 	char	*ptr, *ptrend, *prntptr, *prntptrend;
907*d2d52addSAlexander Pyhalov 	char	*nextptr = NULL, *nextend = NULL;
908*d2d52addSAlexander Pyhalov 	char	*conptr = NULL, *conptrend = NULL;
909*d2d52addSAlexander Pyhalov 	char	*matchptr = NULL;
910*d2d52addSAlexander Pyhalov 	int	conaprnt = 0, conbprnt = 0, lastmatch = 0;
911*d2d52addSAlexander Pyhalov 	boolean_t	nearmatch; /* w/in N+1 of last match */
912*d2d52addSAlexander Pyhalov 	boolean_t	havematch = B_FALSE; /* have a match in context */
913*d2d52addSAlexander Pyhalov 	size_t	prntlen;
914*d2d52addSAlexander Pyhalov 
915*d2d52addSAlexander Pyhalov 	if (patterns == NULL)
916*d2d52addSAlexander Pyhalov 		return (0);	/* no patterns to match -- just return */
917*d2d52addSAlexander Pyhalov 
918*d2d52addSAlexander Pyhalov 	pp = patterns;
919*d2d52addSAlexander Pyhalov 
920*d2d52addSAlexander Pyhalov 	if (use_bmg) {
921*d2d52addSAlexander Pyhalov 		bmgcomp(pp->pattern, strlen(pp->pattern));
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 
924*d2d52addSAlexander Pyhalov 	if (use_wchar && outline == NULL) {
925*d2d52addSAlexander Pyhalov 		outbuflen = BUFSIZE + 1;
926*d2d52addSAlexander Pyhalov 		outline = malloc(sizeof (wchar_t) * outbuflen);
927*d2d52addSAlexander Pyhalov 		if (outline == NULL) {
928*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
929*d2d52addSAlexander Pyhalov 			    cmdname);
930*d2d52addSAlexander Pyhalov 			exit(2);
931*d2d52addSAlexander Pyhalov 		}
932*d2d52addSAlexander Pyhalov 	}
933*d2d52addSAlexander Pyhalov 
934*d2d52addSAlexander Pyhalov 	if (prntbuf == NULL) {
935*d2d52addSAlexander Pyhalov 		prntbuflen = BUFSIZE;
936*d2d52addSAlexander Pyhalov 		if ((prntbuf = malloc(prntbuflen + 1)) == NULL) {
937*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
938*d2d52addSAlexander Pyhalov 			    cmdname);
939*d2d52addSAlexander Pyhalov 			exit(2);
940*d2d52addSAlexander Pyhalov 		}
941*d2d52addSAlexander Pyhalov 	}
942*d2d52addSAlexander Pyhalov 
943*d2d52addSAlexander Pyhalov 	if (conflag != 0 && (conbuf == NULL)) {
944*d2d52addSAlexander Pyhalov 		conbuflen = BUFSIZE;
945*d2d52addSAlexander Pyhalov 		if ((conbuf = malloc(BUFSIZE+1)) == NULL) {
946*d2d52addSAlexander Pyhalov 			(void) fprintf(stderr, gettext("%s: out of memory\n"),
947*d2d52addSAlexander Pyhalov 			    cmdname);
948*d2d52addSAlexander Pyhalov 			exit(2);
949*d2d52addSAlexander Pyhalov 		}
950*d2d52addSAlexander Pyhalov 	}
9517c478bd9Sstevel@tonic-gate 
952*d2d52addSAlexander Pyhalov 	nearmatch = (conmatches != 0);
953*d2d52addSAlexander Pyhalov 	blkoffset = line_offset = 0;
954*d2d52addSAlexander Pyhalov 	lineno = 0;
955*d2d52addSAlexander Pyhalov 	linenum = 1;
956*d2d52addSAlexander Pyhalov 	newlinep = 1;
957*d2d52addSAlexander Pyhalov 	data_len = 0;
958*d2d52addSAlexander Pyhalov 	for (; ; ) {
959*d2d52addSAlexander Pyhalov 		long	count;
960*d2d52addSAlexander Pyhalov 		off_t	offset = 0;
961*d2d52addSAlexander Pyhalov 		char	separate;
962*d2d52addSAlexander Pyhalov 		boolean_t	last_ctx = B_FALSE, eof = B_FALSE;
963*d2d52addSAlexander Pyhalov 
964*d2d52addSAlexander Pyhalov 		if (data_len == 0) {
965*d2d52addSAlexander Pyhalov 			/*
966*d2d52addSAlexander Pyhalov 			 * If no data in the buffer, reset ptr
967*d2d52addSAlexander Pyhalov 			 */
968*d2d52addSAlexander Pyhalov 			ptr = prntbuf;
969*d2d52addSAlexander Pyhalov 			if (conflag != 0 && conptr == NULL) {
970*d2d52addSAlexander Pyhalov 				conptr = conbuf;
971*d2d52addSAlexander Pyhalov 				conptrend = conptr - 1;
972*d2d52addSAlexander Pyhalov 			}
973*d2d52addSAlexander Pyhalov 		}
974*d2d52addSAlexander Pyhalov 		if (ptr == prntbuf) {
9757c478bd9Sstevel@tonic-gate 			/*
976*d2d52addSAlexander Pyhalov 			 * The current data chunk starts from prntbuf.
977*d2d52addSAlexander Pyhalov 			 * This means either the buffer has no data
978*d2d52addSAlexander Pyhalov 			 * or the buffer has no newline.
979*d2d52addSAlexander Pyhalov 			 * So, read more data from input.
9807c478bd9Sstevel@tonic-gate 			 */
981*d2d52addSAlexander Pyhalov 			count = read(fd, ptr + data_len, prntbuflen - data_len);
982*d2d52addSAlexander Pyhalov 			if (count < 0) {
983*d2d52addSAlexander Pyhalov 				/* read error */
984*d2d52addSAlexander Pyhalov 				if (cflag) {
985*d2d52addSAlexander Pyhalov 					if (outfn && !rflag) {
986*d2d52addSAlexander Pyhalov 						(void) fprintf(stdout,
987*d2d52addSAlexander Pyhalov 						    "%s:", fn);
988*d2d52addSAlexander Pyhalov 					}
989*d2d52addSAlexander Pyhalov 					if (!qflag && !rflag) {
990*d2d52addSAlexander Pyhalov 						(void) fprintf(stdout, "%lld\n",
991*d2d52addSAlexander Pyhalov 						    matches);
992*d2d52addSAlexander Pyhalov 					}
993*d2d52addSAlexander Pyhalov 				}
994*d2d52addSAlexander Pyhalov 				return (0);
995*d2d52addSAlexander Pyhalov 			} else if (count == 0) {
996*d2d52addSAlexander Pyhalov 				/* no new data */
997*d2d52addSAlexander Pyhalov 				eof = B_TRUE;
998*d2d52addSAlexander Pyhalov 
999*d2d52addSAlexander Pyhalov 				if (data_len == 0) {
1000*d2d52addSAlexander Pyhalov 					/* end of file already reached */
1001*d2d52addSAlexander Pyhalov 					if (conflag != 0) {
1002*d2d52addSAlexander Pyhalov 						if (conptrend >= conptr)
1003*d2d52addSAlexander Pyhalov 							*conptrend = '\n';
1004*d2d52addSAlexander Pyhalov 						last_ctx = B_TRUE;
1005*d2d52addSAlexander Pyhalov 						goto L_next_line;
1006*d2d52addSAlexander Pyhalov 					} else {
1007*d2d52addSAlexander Pyhalov 						goto out;
1008*d2d52addSAlexander Pyhalov 					}
1009*d2d52addSAlexander Pyhalov 				}
1010*d2d52addSAlexander Pyhalov 				/* last line of file has no newline */
1011*d2d52addSAlexander Pyhalov 				ptrend = ptr + data_len;
1012*d2d52addSAlexander Pyhalov 				newlinep = 0;
1013*d2d52addSAlexander Pyhalov 				goto L_start_process;
1014*d2d52addSAlexander Pyhalov 			}
1015*d2d52addSAlexander Pyhalov 			offset = data_len;
1016*d2d52addSAlexander Pyhalov 			data_len += count;
1017*d2d52addSAlexander Pyhalov 		}
1018*d2d52addSAlexander Pyhalov 
1019*d2d52addSAlexander Pyhalov 		/*
1020*d2d52addSAlexander Pyhalov 		 * Look for newline in the chunk
1021*d2d52addSAlexander Pyhalov 		 * between ptr + offset and ptr + data_len - offset.
1022*d2d52addSAlexander Pyhalov 		 */
1023*d2d52addSAlexander Pyhalov 		ptrend = find_nl(ptr + offset, data_len - offset);
1024*d2d52addSAlexander Pyhalov 		if (ptrend == NULL) {
1025*d2d52addSAlexander Pyhalov 			/* no newline found in this chunk */
10267c478bd9Sstevel@tonic-gate 			if (ptr > prntbuf) {
1027*d2d52addSAlexander Pyhalov 				/*
1028*d2d52addSAlexander Pyhalov 				 * Move remaining data to the beginning
1029*d2d52addSAlexander Pyhalov 				 * of the buffer.
1030*d2d52addSAlexander Pyhalov 				 * Remaining data lie from ptr for
1031*d2d52addSAlexander Pyhalov 				 * data_len bytes.
1032*d2d52addSAlexander Pyhalov 				 */
1033*d2d52addSAlexander Pyhalov 				(void) memmove(prntbuf, ptr, data_len);
10347c478bd9Sstevel@tonic-gate 			}
1035*d2d52addSAlexander Pyhalov 			if (data_len == prntbuflen) {
1036*d2d52addSAlexander Pyhalov 				/*
1037*d2d52addSAlexander Pyhalov 				 * Not enough room in the buffer
1038*d2d52addSAlexander Pyhalov 				 */
1039*d2d52addSAlexander Pyhalov 				if (prntbuflen > SIZE_MAX - BUFSIZE) {
1040*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr,
1041*d2d52addSAlexander Pyhalov 					    gettext("%s: buflen would"
1042*d2d52addSAlexander Pyhalov 					    " overflow\n"),
1043*d2d52addSAlexander Pyhalov 					    cmdname);
1044*d2d52addSAlexander Pyhalov 					exit(2);
1045*d2d52addSAlexander Pyhalov 				}
1046*d2d52addSAlexander Pyhalov 
1047*d2d52addSAlexander Pyhalov 				prntbuflen += BUFSIZE;
1048*d2d52addSAlexander Pyhalov 				prntbuf = realloc(prntbuf, prntbuflen + 1);
1049*d2d52addSAlexander Pyhalov 				if (prntbuf == NULL) {
1050*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr,
1051*d2d52addSAlexander Pyhalov 					    gettext("%s: out of memory\n"),
1052*d2d52addSAlexander Pyhalov 					    cmdname);
1053*d2d52addSAlexander Pyhalov 					exit(2);
1054*d2d52addSAlexander Pyhalov 				}
1055*d2d52addSAlexander Pyhalov 			}
1056*d2d52addSAlexander Pyhalov 			ptr = prntbuf;
1057*d2d52addSAlexander Pyhalov 			/* read the next input */
1058*d2d52addSAlexander Pyhalov 			continue;
1059*d2d52addSAlexander Pyhalov 		}
1060*d2d52addSAlexander Pyhalov L_start_process:
10617c478bd9Sstevel@tonic-gate 
1062*d2d52addSAlexander Pyhalov 		/*
1063*d2d52addSAlexander Pyhalov 		 * Beginning of the chunk:	ptr
1064*d2d52addSAlexander Pyhalov 		 * End of the chunk:		ptr + data_len
1065*d2d52addSAlexander Pyhalov 		 * Beginning of the line:	ptr
1066*d2d52addSAlexander Pyhalov 		 * End of the line:		ptrend
1067*d2d52addSAlexander Pyhalov 		 *
1068*d2d52addSAlexander Pyhalov 		 * conptr:	Beginning of the context.
1069*d2d52addSAlexander Pyhalov 		 * conptrend: If context is empty, conptr - 1 (invalid memory).
1070*d2d52addSAlexander Pyhalov 		 *	Otherwise, Last newline in the context.
1071*d2d52addSAlexander Pyhalov 		 */
1072*d2d52addSAlexander Pyhalov 
1073*d2d52addSAlexander Pyhalov 		if (use_bmg) {
10747c478bd9Sstevel@tonic-gate 			/*
1075*d2d52addSAlexander Pyhalov 			 * Use Boyer-Moore-Gosper algorithm to find out if
1076*d2d52addSAlexander Pyhalov 			 * this chunk (not this line) contains the specified
1077*d2d52addSAlexander Pyhalov 			 * pattern.  If not, restart from the last line
1078*d2d52addSAlexander Pyhalov 			 * of this chunk.
10797c478bd9Sstevel@tonic-gate 			 */
1080*d2d52addSAlexander Pyhalov 			char	*bline;
1081*d2d52addSAlexander Pyhalov 			bline = bmgexec(ptr, ptr + data_len);
1082*d2d52addSAlexander Pyhalov 			if (bline == NULL) {
10837c478bd9Sstevel@tonic-gate 				/*
1084*d2d52addSAlexander Pyhalov 				 * No pattern found in this chunk.
1085*d2d52addSAlexander Pyhalov 				 * Need to find the last line
1086*d2d52addSAlexander Pyhalov 				 * in this chunk.
10877c478bd9Sstevel@tonic-gate 				 */
1088*d2d52addSAlexander Pyhalov 				ptrend = rfind_nl(ptr, data_len);
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 				/*
1091*d2d52addSAlexander Pyhalov 				 * When this chunk does not contain newline,
1092*d2d52addSAlexander Pyhalov 				 * ptrend becomes NULL, which should happen
1093*d2d52addSAlexander Pyhalov 				 * when the last line of file does not end
1094*d2d52addSAlexander Pyhalov 				 * with a newline.  At such a point,
1095*d2d52addSAlexander Pyhalov 				 * newlinep should have been set to 0.
1096*d2d52addSAlexander Pyhalov 				 * Therefore, just after jumping to
1097*d2d52addSAlexander Pyhalov 				 * L_skip_line, the main for-loop quits,
1098*d2d52addSAlexander Pyhalov 				 * and the line_len value won't be
1099*d2d52addSAlexander Pyhalov 				 * used.
1100*d2d52addSAlexander Pyhalov 				 */
1101*d2d52addSAlexander Pyhalov 				line_len = ptrend - ptr;
1102*d2d52addSAlexander Pyhalov 				goto L_skip_line;
1103*d2d52addSAlexander Pyhalov 			}
1104*d2d52addSAlexander Pyhalov 			if (bline > ptrend) {
1105*d2d52addSAlexander Pyhalov 				/*
1106*d2d52addSAlexander Pyhalov 				 * Pattern found not in the first line
1107*d2d52addSAlexander Pyhalov 				 * of this chunk.
1108*d2d52addSAlexander Pyhalov 				 * Discard the first line.
11097c478bd9Sstevel@tonic-gate 				 */
1110*d2d52addSAlexander Pyhalov 				line_len = ptrend - ptr;
1111*d2d52addSAlexander Pyhalov 				goto L_skip_line;
1112*d2d52addSAlexander Pyhalov 			}
1113*d2d52addSAlexander Pyhalov 			/*
1114*d2d52addSAlexander Pyhalov 			 * Pattern found in the first line of this chunk.
1115*d2d52addSAlexander Pyhalov 			 * Using this result.
1116*d2d52addSAlexander Pyhalov 			 */
1117*d2d52addSAlexander Pyhalov 			*ptrend = '\0';
1118*d2d52addSAlexander Pyhalov 			line_len = ptrend - ptr;
1119*d2d52addSAlexander Pyhalov 
1120*d2d52addSAlexander Pyhalov 			/*
1121*d2d52addSAlexander Pyhalov 			 * before jumping to L_next_line,
1122*d2d52addSAlexander Pyhalov 			 * need to handle xflag if specified
1123*d2d52addSAlexander Pyhalov 			 */
1124*d2d52addSAlexander Pyhalov 			if (xflag && (line_len != bmglen ||
1125*d2d52addSAlexander Pyhalov 			    strcmp(bmgpat, ptr) != 0)) {
1126*d2d52addSAlexander Pyhalov 				/* didn't match */
1127*d2d52addSAlexander Pyhalov 				pp = NULL;
1128*d2d52addSAlexander Pyhalov 			} else {
1129*d2d52addSAlexander Pyhalov 				pp = patterns; /* to make it happen */
1130*d2d52addSAlexander Pyhalov 			}
1131*d2d52addSAlexander Pyhalov 			goto L_next_line;
1132*d2d52addSAlexander Pyhalov 		}
1133*d2d52addSAlexander Pyhalov 		lineno++;
1134*d2d52addSAlexander Pyhalov 		/*
1135*d2d52addSAlexander Pyhalov 		 * Line starts from ptr and ends at ptrend.
1136*d2d52addSAlexander Pyhalov 		 * line_len will be the length of the line.
1137*d2d52addSAlexander Pyhalov 		 */
1138*d2d52addSAlexander Pyhalov 		*ptrend = '\0';
1139*d2d52addSAlexander Pyhalov 		line_len = ptrend - ptr;
1140*d2d52addSAlexander Pyhalov 
1141*d2d52addSAlexander Pyhalov 		/*
1142*d2d52addSAlexander Pyhalov 		 * From now, the process will be performed based
1143*d2d52addSAlexander Pyhalov 		 * on the line from ptr to ptrend.
1144*d2d52addSAlexander Pyhalov 		 */
1145*d2d52addSAlexander Pyhalov 		if (use_wchar) {
1146*d2d52addSAlexander Pyhalov 			size_t	len;
1147*d2d52addSAlexander Pyhalov 
1148*d2d52addSAlexander Pyhalov 			if (line_len >= outbuflen) {
1149*d2d52addSAlexander Pyhalov 				outbuflen = line_len + 1;
1150*d2d52addSAlexander Pyhalov 				outline = realloc(outline,
1151*d2d52addSAlexander Pyhalov 				    sizeof (wchar_t) * outbuflen);
1152*d2d52addSAlexander Pyhalov 				if (outline == NULL) {
1153*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr,
1154*d2d52addSAlexander Pyhalov 					    gettext("%s: out of memory\n"),
1155*d2d52addSAlexander Pyhalov 					    cmdname);
11567c478bd9Sstevel@tonic-gate 					exit(2);
1157*d2d52addSAlexander Pyhalov 				}
1158*d2d52addSAlexander Pyhalov 			}
11597c478bd9Sstevel@tonic-gate 
1160*d2d52addSAlexander Pyhalov 			len = mbstowcs(outline, ptr, line_len);
1161*d2d52addSAlexander Pyhalov 			if (len == (size_t)-1) {
1162*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr, gettext(
1163*d2d52addSAlexander Pyhalov 	"%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1164*d2d52addSAlexander Pyhalov 				    cmdname, fn, lineno);
1165*d2d52addSAlexander Pyhalov 				/* never match a line with invalid sequence */
1166*d2d52addSAlexander Pyhalov 				goto L_skip_line;
11677c478bd9Sstevel@tonic-gate 			}
1168*d2d52addSAlexander Pyhalov 			outline[len] = L'\0';
11697c478bd9Sstevel@tonic-gate 
1170*d2d52addSAlexander Pyhalov 			if (iflag) {
1171*d2d52addSAlexander Pyhalov 				wchar_t	*cp;
1172*d2d52addSAlexander Pyhalov 				for (cp = outline; *cp != '\0'; cp++) {
1173*d2d52addSAlexander Pyhalov 					*cp = towlower((wint_t)*cp);
1174*d2d52addSAlexander Pyhalov 				}
1175*d2d52addSAlexander Pyhalov 			}
11767c478bd9Sstevel@tonic-gate 
1177*d2d52addSAlexander Pyhalov 			if (xflag) {
1178*d2d52addSAlexander Pyhalov 				for (pp = patterns; pp; pp = pp->next) {
1179*d2d52addSAlexander Pyhalov 					if (outline[0] == pp->wpattern[0] &&
1180*d2d52addSAlexander Pyhalov 					    wcscmp(outline,
1181*d2d52addSAlexander Pyhalov 					    pp->wpattern) == 0) {
1182*d2d52addSAlexander Pyhalov 						/* matched */
1183*d2d52addSAlexander Pyhalov 						break;
1184*d2d52addSAlexander Pyhalov 					}
1185*d2d52addSAlexander Pyhalov 				}
1186*d2d52addSAlexander Pyhalov 			} else {
1187*d2d52addSAlexander Pyhalov 				for (pp = patterns; pp; pp = pp->next) {
1188*d2d52addSAlexander Pyhalov 					if (wcswcs(outline, pp->wpattern)
1189*d2d52addSAlexander Pyhalov 					    != NULL) {
1190*d2d52addSAlexander Pyhalov 						/* matched */
1191*d2d52addSAlexander Pyhalov 						break;
1192*d2d52addSAlexander Pyhalov 					}
1193*d2d52addSAlexander Pyhalov 				}
1194*d2d52addSAlexander Pyhalov 			}
1195*d2d52addSAlexander Pyhalov 		} else if (Fflag) {
1196*d2d52addSAlexander Pyhalov 			/* fgrep in byte-oriented handling */
1197*d2d52addSAlexander Pyhalov 			char	*fptr;
1198*d2d52addSAlexander Pyhalov 			if (iflag) {
1199*d2d52addSAlexander Pyhalov 				fptr = istrdup(ptr);
1200*d2d52addSAlexander Pyhalov 			} else {
1201*d2d52addSAlexander Pyhalov 				fptr = ptr;
1202*d2d52addSAlexander Pyhalov 			}
1203*d2d52addSAlexander Pyhalov 			if (xflag) {
1204*d2d52addSAlexander Pyhalov 				/* fgrep -x */
1205*d2d52addSAlexander Pyhalov 				for (pp = patterns; pp; pp = pp->next) {
1206*d2d52addSAlexander Pyhalov 					if (fptr[0] == pp->pattern[0] &&
1207*d2d52addSAlexander Pyhalov 					    strcmp(fptr, pp->pattern) == 0) {
1208*d2d52addSAlexander Pyhalov 						/* matched */
1209*d2d52addSAlexander Pyhalov 						break;
1210*d2d52addSAlexander Pyhalov 					}
1211*d2d52addSAlexander Pyhalov 				}
1212*d2d52addSAlexander Pyhalov 			} else {
1213*d2d52addSAlexander Pyhalov 				for (pp = patterns; pp; pp = pp->next) {
1214*d2d52addSAlexander Pyhalov 					if (strstr(fptr, pp->pattern) != NULL) {
1215*d2d52addSAlexander Pyhalov 						/* matched */
1216*d2d52addSAlexander Pyhalov 						break;
1217*d2d52addSAlexander Pyhalov 					}
1218*d2d52addSAlexander Pyhalov 				}
1219*d2d52addSAlexander Pyhalov 			}
1220*d2d52addSAlexander Pyhalov 		} else {
1221*d2d52addSAlexander Pyhalov 			/* grep or egrep */
1222*d2d52addSAlexander Pyhalov 			for (pp = patterns; pp; pp = pp->next) {
1223*d2d52addSAlexander Pyhalov 				int	rv;
12247c478bd9Sstevel@tonic-gate 
1225*d2d52addSAlexander Pyhalov 				rv = regexec(&pp->re, ptr, 0, NULL, 0);
1226*d2d52addSAlexander Pyhalov 				if (rv == REG_OK) {
1227*d2d52addSAlexander Pyhalov 					/* matched */
1228*d2d52addSAlexander Pyhalov 					break;
1229*d2d52addSAlexander Pyhalov 				}
1230*d2d52addSAlexander Pyhalov 
1231*d2d52addSAlexander Pyhalov 				switch (rv) {
1232*d2d52addSAlexander Pyhalov 				case REG_NOMATCH:
1233*d2d52addSAlexander Pyhalov 					break;
1234*d2d52addSAlexander Pyhalov 				case REG_ECHAR:
1235*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr, gettext(
1236*d2d52addSAlexander Pyhalov 	    "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1237*d2d52addSAlexander Pyhalov 					    cmdname, fn, lineno);
1238*d2d52addSAlexander Pyhalov 					break;
1239*d2d52addSAlexander Pyhalov 				default:
1240*d2d52addSAlexander Pyhalov 					(void) regerror(rv, &pp->re, errstr,
1241*d2d52addSAlexander Pyhalov 					    sizeof (errstr));
1242*d2d52addSAlexander Pyhalov 					(void) fprintf(stderr, gettext(
1243*d2d52addSAlexander Pyhalov 	    "%s: input file \"%s\": line %lld: %s\n"),
1244*d2d52addSAlexander Pyhalov 					    cmdname, fn, lineno, errstr);
1245*d2d52addSAlexander Pyhalov 					exit(2);
1246*d2d52addSAlexander Pyhalov 				}
1247*d2d52addSAlexander Pyhalov 			}
1248*d2d52addSAlexander Pyhalov 		}
1249*d2d52addSAlexander Pyhalov 
1250*d2d52addSAlexander Pyhalov 		/*
1251*d2d52addSAlexander Pyhalov 		 * Context is set up as follows:
1252*d2d52addSAlexander Pyhalov 		 * For a 'Before' context, we maintain a set of pointers
1253*d2d52addSAlexander Pyhalov 		 * containing 'N' lines of context. If the current number of
1254*d2d52addSAlexander Pyhalov 		 * lines contained is greater than N, and N isn't a match, the
1255*d2d52addSAlexander Pyhalov 		 * start pointer is moved forward to the next newline.
1256*d2d52addSAlexander Pyhalov 		 *
1257*d2d52addSAlexander Pyhalov 		 * If we ever find a match, we print out immediately.
1258*d2d52addSAlexander Pyhalov 		 * 'nearmatch' tells us if we're within N+1 lines of the last
1259*d2d52addSAlexander Pyhalov 		 * match ; if we are, and we find another match, we don't
1260*d2d52addSAlexander Pyhalov 		 * separate the matches. 'nearmatch' becomes false when
1261*d2d52addSAlexander Pyhalov 		 * a line gets rotated out of the context.
1262*d2d52addSAlexander Pyhalov 		 *
1263*d2d52addSAlexander Pyhalov 		 * For an 'After' context, we simply wait until we've found a
1264*d2d52addSAlexander Pyhalov 		 * match, then create a context N+1 lines big. If we don't find
1265*d2d52addSAlexander Pyhalov 		 * a match within the context, we print out the current context.
1266*d2d52addSAlexander Pyhalov 		 * Otherwise, we save a reference to the new matching line,
1267*d2d52addSAlexander Pyhalov 		 * print out the other context, and reset our context pointers
1268*d2d52addSAlexander Pyhalov 		 * to the new matching line.
1269*d2d52addSAlexander Pyhalov 		 *
1270*d2d52addSAlexander Pyhalov 		 * 'nearmatch' becomes false when we find a non-matching line
1271*d2d52addSAlexander Pyhalov 		 * that isn't a part of any context.
1272*d2d52addSAlexander Pyhalov 		 *
1273*d2d52addSAlexander Pyhalov 		 * A full-context is implemented as a combination of the
1274*d2d52addSAlexander Pyhalov 		 * 'Before' and 'After' context logic. Before we find a match,
1275*d2d52addSAlexander Pyhalov 		 * we follow the Before logic. When we find a match, we
1276*d2d52addSAlexander Pyhalov 		 * follow the After logic. 'nearmatch' is handled by the Before
1277*d2d52addSAlexander Pyhalov 		 * logic.
1278*d2d52addSAlexander Pyhalov 		 */
1279*d2d52addSAlexander Pyhalov 
1280*d2d52addSAlexander Pyhalov 		if (conflag == 0)
1281*d2d52addSAlexander Pyhalov 			goto L_next_line;
1282*d2d52addSAlexander Pyhalov 
1283*d2d52addSAlexander Pyhalov 		/* Do we have room to add this line to the context buffer? */
1284*d2d52addSAlexander Pyhalov 		if ((line_len + 1) > (conbuflen -
1285*d2d52addSAlexander Pyhalov 		    (conptrend >= conptr) ? conptrend - conbuf : 0)) {
1286*d2d52addSAlexander Pyhalov 			char *oldconbuf = conbuf;
1287*d2d52addSAlexander Pyhalov 			char *oldconptr = conptr;
1288*d2d52addSAlexander Pyhalov 			long tmp = matchptr - conptr;
1289*d2d52addSAlexander Pyhalov 
1290*d2d52addSAlexander Pyhalov 			if (conbuflen > SIZE_MAX - BUFSIZE) {
1291*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
1292*d2d52addSAlexander Pyhalov 				    gettext("%s: buflen would overflow\n"),
1293*d2d52addSAlexander Pyhalov 				    cmdname);
1294*d2d52addSAlexander Pyhalov 				exit(2);
1295*d2d52addSAlexander Pyhalov 			}
1296*d2d52addSAlexander Pyhalov 
1297*d2d52addSAlexander Pyhalov 			conbuflen += BUFSIZE;
1298*d2d52addSAlexander Pyhalov 			conbuf = realloc(conbuf, conbuflen + 1);
1299*d2d52addSAlexander Pyhalov 			if (conbuf == NULL) {
1300*d2d52addSAlexander Pyhalov 				(void) fprintf(stderr,
1301*d2d52addSAlexander Pyhalov 				    gettext("%s: out of memory\n"),
1302*d2d52addSAlexander Pyhalov 				    cmdname);
1303*d2d52addSAlexander Pyhalov 				exit(2);
1304*d2d52addSAlexander Pyhalov 			}
1305*d2d52addSAlexander Pyhalov 
1306*d2d52addSAlexander Pyhalov 			conptr = conbuf + (conptr - oldconbuf);
1307*d2d52addSAlexander Pyhalov 			conptrend = conptr + (conptrend - oldconptr);
1308*d2d52addSAlexander Pyhalov 			if (matchptr)
1309*d2d52addSAlexander Pyhalov 				matchptr = conptr + tmp;
1310*d2d52addSAlexander Pyhalov 		}
1311*d2d52addSAlexander Pyhalov 		(void) memcpy(conptrend + 1, ptr, line_len);
1312*d2d52addSAlexander Pyhalov 		conptrend += line_len + 1;
1313*d2d52addSAlexander Pyhalov 		*conptrend = '\n';
1314*d2d52addSAlexander Pyhalov 
1315*d2d52addSAlexander Pyhalov 		if (nvflag == (pp != NULL)) {
1316*d2d52addSAlexander Pyhalov 			/* matched */
1317*d2d52addSAlexander Pyhalov 			if (havematch) {
1318*d2d52addSAlexander Pyhalov 				if ((conflag & AFTER) != 0) {
1319*d2d52addSAlexander Pyhalov 					conaprnt = 1;
1320*d2d52addSAlexander Pyhalov 					nextend = conptrend;
1321*d2d52addSAlexander Pyhalov 					conptrend = conptr + lastmatch;
1322*d2d52addSAlexander Pyhalov 					nextptr = conptrend + 1;
1323*d2d52addSAlexander Pyhalov 					*nextend = '\n';
1324*d2d52addSAlexander Pyhalov 				}
1325*d2d52addSAlexander Pyhalov 			} else {
1326*d2d52addSAlexander Pyhalov 				if (conflag == AFTER) {
1327*d2d52addSAlexander Pyhalov 					conptr = conptrend - (line_len);
1328*d2d52addSAlexander Pyhalov 					linenum = lineno;
1329*d2d52addSAlexander Pyhalov 				}
1330*d2d52addSAlexander Pyhalov 				blkoffset = line_offset -
1331*d2d52addSAlexander Pyhalov 				    (conptrend - conptr - line_len);
1332*d2d52addSAlexander Pyhalov 			}
1333*d2d52addSAlexander Pyhalov 
1334*d2d52addSAlexander Pyhalov 			if (conflag == BEFORE)
1335*d2d52addSAlexander Pyhalov 				conbprnt = 1;
1336*d2d52addSAlexander Pyhalov 
1337*d2d52addSAlexander Pyhalov 			lastmatch = conptrend - conptr;
1338*d2d52addSAlexander Pyhalov 			havematch = B_TRUE;
1339*d2d52addSAlexander Pyhalov 			goto L_next_line;
1340*d2d52addSAlexander Pyhalov 		}
1341*d2d52addSAlexander Pyhalov 
1342*d2d52addSAlexander Pyhalov 		if (!havematch) {
1343*d2d52addSAlexander Pyhalov 			if ((conflag & BEFORE) != 0) {
1344*d2d52addSAlexander Pyhalov 				if (conbcnt >= conblen) {
1345*d2d52addSAlexander Pyhalov 					char *tmp = conptr;
1346*d2d52addSAlexander Pyhalov 					conptr = find_nl(conptr,
1347*d2d52addSAlexander Pyhalov 					    conptrend - conptr) + 1;
1348*d2d52addSAlexander Pyhalov 					if (bflag)
1349*d2d52addSAlexander Pyhalov 						blkoffset += conptr - tmp;
1350*d2d52addSAlexander Pyhalov 					linenum++;
1351*d2d52addSAlexander Pyhalov 					nearmatch = B_TRUE;
1352*d2d52addSAlexander Pyhalov 				} else {
1353*d2d52addSAlexander Pyhalov 					conbcnt++;
1354*d2d52addSAlexander Pyhalov 				}
1355*d2d52addSAlexander Pyhalov 			}
1356*d2d52addSAlexander Pyhalov 			if (conflag == AFTER)
1357*d2d52addSAlexander Pyhalov 				nearmatch = B_TRUE;
1358*d2d52addSAlexander Pyhalov 		} else  {
1359*d2d52addSAlexander Pyhalov 			if (++conacnt >= conalen && !conaprnt && conalen)
1360*d2d52addSAlexander Pyhalov 				conaprnt = 1;
1361*d2d52addSAlexander Pyhalov 			else
1362*d2d52addSAlexander Pyhalov 				lastmatch = conptrend - conptr;
1363*d2d52addSAlexander Pyhalov 		}
1364*d2d52addSAlexander Pyhalov 
1365*d2d52addSAlexander Pyhalov L_next_line:
1366*d2d52addSAlexander Pyhalov 		/*
1367*d2d52addSAlexander Pyhalov 		 * Here, if pp points to non-NULL, something has been matched
1368*d2d52addSAlexander Pyhalov 		 * to the pattern.
1369*d2d52addSAlexander Pyhalov 		 */
1370*d2d52addSAlexander Pyhalov 		if (!last_ctx && nvflag == (pp != NULL)) {
1371*d2d52addSAlexander Pyhalov 			matches++;
1372*d2d52addSAlexander Pyhalov 			if (!nextend)
1373*d2d52addSAlexander Pyhalov 				matchptr = (conflag != 0) ? conptrend : ptrend;
1374*d2d52addSAlexander Pyhalov 		}
1375*d2d52addSAlexander Pyhalov 
1376*d2d52addSAlexander Pyhalov 		/*
1377*d2d52addSAlexander Pyhalov 		 * Set up some print context so that we can treat
1378*d2d52addSAlexander Pyhalov 		 * single-line matches as a zero-N context.
1379*d2d52addSAlexander Pyhalov 		 * Apply CLI flags to each line of the context.
1380*d2d52addSAlexander Pyhalov 		 *
1381*d2d52addSAlexander Pyhalov 		 * For context, we only print if we both have a match and are
1382*d2d52addSAlexander Pyhalov 		 * either at the end of the data stream, or we've previously
1383*d2d52addSAlexander Pyhalov 		 * declared that we want to print for a particular context.
1384*d2d52addSAlexander Pyhalov 		 */
1385*d2d52addSAlexander Pyhalov 		if (havematch && (eof || conaprnt || conbprnt)) {
1386*d2d52addSAlexander Pyhalov 
1387*d2d52addSAlexander Pyhalov 			/*
1388*d2d52addSAlexander Pyhalov 			 * We'd normally do this earlier, but we had to
1389*d2d52addSAlexander Pyhalov 			 * escape early because we reached the end of the data.
1390*d2d52addSAlexander Pyhalov 			 */
1391*d2d52addSAlexander Pyhalov 			if (eof && nextptr)
1392*d2d52addSAlexander Pyhalov 				conptrend = nextend;
1393*d2d52addSAlexander Pyhalov 
1394*d2d52addSAlexander Pyhalov 			prntlen = conptrend - conptr + 1;
1395*d2d52addSAlexander Pyhalov 			prntptr = conptr;
1396*d2d52addSAlexander Pyhalov 			if (conmatches++ && nearmatch && !cflag)
1397*d2d52addSAlexander Pyhalov 				(void) fwrite("--\n", 1, 3, stdout);
1398*d2d52addSAlexander Pyhalov 		} else if (conflag == 0 && nvflag == (pp != NULL)) {
1399*d2d52addSAlexander Pyhalov 			*ptrend = '\n';
1400*d2d52addSAlexander Pyhalov 			prntlen = line_len + 1;
1401*d2d52addSAlexander Pyhalov 			prntptr = ptr;
1402*d2d52addSAlexander Pyhalov 			linenum = lineno;
1403*d2d52addSAlexander Pyhalov 			blkoffset = line_offset;
1404*d2d52addSAlexander Pyhalov 		} else if (eof) {
1405*d2d52addSAlexander Pyhalov 			/* No match and no more data */
1406*d2d52addSAlexander Pyhalov 			goto out;
14077c478bd9Sstevel@tonic-gate 		} else {
1408*d2d52addSAlexander Pyhalov 			/* No match, or we're not done building context */
1409*d2d52addSAlexander Pyhalov 			goto L_skip_line;
14107c478bd9Sstevel@tonic-gate 		}
14117c478bd9Sstevel@tonic-gate 
1412*d2d52addSAlexander Pyhalov 		prntptrend = prntptr - 1;
1413*d2d52addSAlexander Pyhalov 		while ((prntptrend = find_nl(prntptrend + 1,
1414*d2d52addSAlexander Pyhalov 		    prntlen)) != NULL) {
1415*d2d52addSAlexander Pyhalov 
14167c478bd9Sstevel@tonic-gate 			/*
1417*d2d52addSAlexander Pyhalov 			 * GNU grep uses '-' for context lines and ':' for
1418*d2d52addSAlexander Pyhalov 			 * matching lines, so replicate that here.
14197c478bd9Sstevel@tonic-gate 			 */
1420*d2d52addSAlexander Pyhalov 			if (prntptrend == matchptr) {
1421*d2d52addSAlexander Pyhalov 				if (eof && nextptr) {
1422*d2d52addSAlexander Pyhalov 					matchptr = nextend;
1423*d2d52addSAlexander Pyhalov 					nextptr = NULL;
1424*d2d52addSAlexander Pyhalov 				} else {
1425*d2d52addSAlexander Pyhalov 					matchptr = NULL;
1426*d2d52addSAlexander Pyhalov 				}
1427*d2d52addSAlexander Pyhalov 				separate = ':';
1428*d2d52addSAlexander Pyhalov 			} else {
1429*d2d52addSAlexander Pyhalov 				separate = '-';
1430*d2d52addSAlexander Pyhalov 			}
1431*d2d52addSAlexander Pyhalov 
14327c478bd9Sstevel@tonic-gate 			/*
1433*d2d52addSAlexander Pyhalov 			 * Handle q, l, and c flags.
14347c478bd9Sstevel@tonic-gate 			 */
1435*d2d52addSAlexander Pyhalov 			if (qflag) {
1436*d2d52addSAlexander Pyhalov 				/* no need to continue */
1437*d2d52addSAlexander Pyhalov 				/*
1438*d2d52addSAlexander Pyhalov 				 * End of this line is ptrend.
1439*d2d52addSAlexander Pyhalov 				 * We have read up to ptr + data_len.
1440*d2d52addSAlexander Pyhalov 				 */
1441*d2d52addSAlexander Pyhalov 				off_t	pos;
1442*d2d52addSAlexander Pyhalov 				pos = ptr + data_len - (ptrend + 1);
1443*d2d52addSAlexander Pyhalov 				(void) lseek(fd, -pos, SEEK_CUR);
1444*d2d52addSAlexander Pyhalov 				exit(0);
1445*d2d52addSAlexander Pyhalov 			}
1446*d2d52addSAlexander Pyhalov 			if (lflag) {
1447*d2d52addSAlexander Pyhalov 				(void) printf("%s\n", fn);
1448*d2d52addSAlexander Pyhalov 				goto out;
1449*d2d52addSAlexander Pyhalov 			}
1450*d2d52addSAlexander Pyhalov 			if (!cflag) {
1451*d2d52addSAlexander Pyhalov 				if (Hflag || outfn) {
1452*d2d52addSAlexander Pyhalov 					(void) printf("%s%c", fn, separate);
1453*d2d52addSAlexander Pyhalov 				}
1454*d2d52addSAlexander Pyhalov 				if (bflag) {
1455*d2d52addSAlexander Pyhalov 					(void) printf("%lld%c", (offset_t)
1456*d2d52addSAlexander Pyhalov 					    (blkoffset / BSIZE), separate);
1457*d2d52addSAlexander Pyhalov 				}
1458*d2d52addSAlexander Pyhalov 				if (nflag) {
1459*d2d52addSAlexander Pyhalov 					(void) printf("%lld%c", linenum,
1460*d2d52addSAlexander Pyhalov 					    separate);
1461*d2d52addSAlexander Pyhalov 				}
1462*d2d52addSAlexander Pyhalov 				(void) fwrite(prntptr, 1,
1463*d2d52addSAlexander Pyhalov 				    prntptrend - prntptr + 1, stdout);
1464*d2d52addSAlexander Pyhalov 			}
1465*d2d52addSAlexander Pyhalov 			if (ferror(stdout)) {
1466*d2d52addSAlexander Pyhalov 				return (0);
1467*d2d52addSAlexander Pyhalov 			}
1468*d2d52addSAlexander Pyhalov 			linenum++;
1469*d2d52addSAlexander Pyhalov 			prntlen -= prntptrend - prntptr + 1;
1470*d2d52addSAlexander Pyhalov 			blkoffset += prntptrend - prntptr + 1;
1471*d2d52addSAlexander Pyhalov 			prntptr = prntptrend + 1;
1472*d2d52addSAlexander Pyhalov 		}
14737c478bd9Sstevel@tonic-gate 
1474*d2d52addSAlexander Pyhalov 		if (eof)
1475*d2d52addSAlexander Pyhalov 			goto out;
1476*d2d52addSAlexander Pyhalov 
1477*d2d52addSAlexander Pyhalov 		/*
1478*d2d52addSAlexander Pyhalov 		 * Update context buffer and variables post-print
1479*d2d52addSAlexander Pyhalov 		 */
1480*d2d52addSAlexander Pyhalov 		if (conflag != 0) {
1481*d2d52addSAlexander Pyhalov 			conptr = conbuf;
1482*d2d52addSAlexander Pyhalov 			conaprnt = conbprnt = 0;
1483*d2d52addSAlexander Pyhalov 			nearmatch = B_FALSE;
1484*d2d52addSAlexander Pyhalov 			conacnt = conbcnt = 0;
1485*d2d52addSAlexander Pyhalov 
1486*d2d52addSAlexander Pyhalov 			if (nextptr) {
1487*d2d52addSAlexander Pyhalov 				(void) memmove(conbuf, nextptr,
1488*d2d52addSAlexander Pyhalov 				    nextend - nextptr + 1);
1489*d2d52addSAlexander Pyhalov 				blkoffset += nextptr - conptrend - 1;
1490*d2d52addSAlexander Pyhalov 				conptrend = conptr + (nextend - nextptr);
1491*d2d52addSAlexander Pyhalov 				matchptr = conptrend;
1492*d2d52addSAlexander Pyhalov 				linenum = lineno;
1493*d2d52addSAlexander Pyhalov 				lastmatch = conptrend - conptr;
1494*d2d52addSAlexander Pyhalov 				havematch = B_TRUE;
1495*d2d52addSAlexander Pyhalov 			} else {
1496*d2d52addSAlexander Pyhalov 				conptrend = conptr - 1;
1497*d2d52addSAlexander Pyhalov 				conacnt = 0;
1498*d2d52addSAlexander Pyhalov 				lastmatch = 0;
1499*d2d52addSAlexander Pyhalov 				havematch = B_FALSE;
1500*d2d52addSAlexander Pyhalov 			}
1501*d2d52addSAlexander Pyhalov 			nextptr = nextend = NULL;
1502*d2d52addSAlexander Pyhalov 		}
15037c478bd9Sstevel@tonic-gate 
1504*d2d52addSAlexander Pyhalov L_skip_line:
1505*d2d52addSAlexander Pyhalov 		if (!newlinep)
15067c478bd9Sstevel@tonic-gate 			break;
15077c478bd9Sstevel@tonic-gate 
1508*d2d52addSAlexander Pyhalov 		data_len -= line_len + 1;
1509*d2d52addSAlexander Pyhalov 		line_offset += line_len + 1;
1510*d2d52addSAlexander Pyhalov 		ptr = ptrend + 1;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 
1513*d2d52addSAlexander Pyhalov out:
1514*d2d52addSAlexander Pyhalov 	if (cflag) {
1515*d2d52addSAlexander Pyhalov 		if (Hflag || outfn) {
1516*d2d52addSAlexander Pyhalov 			(void) printf("%s:", fn);
1517*d2d52addSAlexander Pyhalov 		}
1518*d2d52addSAlexander Pyhalov 		if (!qflag) {
1519*d2d52addSAlexander Pyhalov 			(void) printf("%lld\n", matches);
1520*d2d52addSAlexander Pyhalov 		}
15217c478bd9Sstevel@tonic-gate 	}
1522*d2d52addSAlexander Pyhalov 	return (matches != 0);
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate 
1525*d2d52addSAlexander Pyhalov /*
1526*d2d52addSAlexander Pyhalov  * usage message for grep
1527*d2d52addSAlexander Pyhalov  */
1528*d2d52addSAlexander Pyhalov static void
1529*d2d52addSAlexander Pyhalov usage(void)
15307c478bd9Sstevel@tonic-gate {
1531*d2d52addSAlexander Pyhalov 	if (egrep || fgrep) {
1532*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1533*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1534*d2d52addSAlexander Pyhalov 		    gettext(" [-c|-l|-q] [-r|-R] "
1535*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1536*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] pattern_list [file ...]\n"));
15377c478bd9Sstevel@tonic-gate 
1538*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, "\t%s", cmdname);
1539*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1540*d2d52addSAlexander Pyhalov 		    gettext(" [-c|-l|-q] [-r|-R] "
1541*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1542*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] [-e pattern_list]... "
1543*d2d52addSAlexander Pyhalov 		    "[-f pattern_file]... [file...]\n"));
1544*d2d52addSAlexander Pyhalov 	} else {
1545*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1546*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1547*d2d52addSAlexander Pyhalov 		    gettext(" [-c|-l|-q] [-r|-R] "
1548*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1549*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] pattern_list [file ...]\n"));
15503ed621bcSAlexander Eremin 
1551*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, "\t%s", cmdname);
1552*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1553*d2d52addSAlexander Pyhalov 		    gettext(" [-c|-l|-q] [-r|-R] "
1554*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1555*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] [-e pattern_list]... "
1556*d2d52addSAlexander Pyhalov 		    "[-f pattern_file]... [file...]\n"));
15577c478bd9Sstevel@tonic-gate 
1558*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, "\t%s", cmdname);
1559*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1560*d2d52addSAlexander Pyhalov 		    gettext(" -E [-c|-l|-q] [-r|-R] "
1561*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1562*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] pattern_list [file ...]\n"));
15637c478bd9Sstevel@tonic-gate 
1564*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, "\t%s", cmdname);
1565*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1566*d2d52addSAlexander Pyhalov 		    gettext(" -E [-c|-l|-q] [-r|-R] "
1567*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1568*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] [-e pattern_list]... "
1569*d2d52addSAlexander Pyhalov 		    "[-f pattern_file]... [file...]\n"));
1570*d2d52addSAlexander Pyhalov 
1571*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, "\t%s", cmdname);
1572*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1573*d2d52addSAlexander Pyhalov 		    gettext(" -F [-c|-l|-q] [-r|-R] "
1574*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1575*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] pattern_list [file ...]\n"));
1576*d2d52addSAlexander Pyhalov 
1577*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr, "\t%s", cmdname);
1578*d2d52addSAlexander Pyhalov 		(void) fprintf(stderr,
1579*d2d52addSAlexander Pyhalov 		    gettext(" -F [-c|-l|-q] "
1580*d2d52addSAlexander Pyhalov 		    "[-A num] [-B num] [-C num|-num] "
1581*d2d52addSAlexander Pyhalov 		    "[-bhHinsvx] [-e pattern_list]... "
1582*d2d52addSAlexander Pyhalov 		    "[-f pattern_file]... [file...]\n"));
1583e52fb54bSAlexander Eremin 	}
1584*d2d52addSAlexander Pyhalov 	exit(2);
1585*d2d52addSAlexander Pyhalov 	/* NOTREACHED */
1586*d2d52addSAlexander Pyhalov }
15877c478bd9Sstevel@tonic-gate 
1588*d2d52addSAlexander Pyhalov /*
1589*d2d52addSAlexander Pyhalov  * Compile literal pattern into BMG tables
1590*d2d52addSAlexander Pyhalov  */
1591*d2d52addSAlexander Pyhalov static void
1592*d2d52addSAlexander Pyhalov bmgcomp(char *pat, int len)
1593*d2d52addSAlexander Pyhalov {
1594*d2d52addSAlexander Pyhalov 	int	i;
1595*d2d52addSAlexander Pyhalov 	int	tlen;
1596*d2d52addSAlexander Pyhalov 	unsigned char	*uc = (unsigned char *)pat;
15977c478bd9Sstevel@tonic-gate 
1598*d2d52addSAlexander Pyhalov 	bmglen = len;
1599*d2d52addSAlexander Pyhalov 	bmgpat = pat;
16007c478bd9Sstevel@tonic-gate 
1601*d2d52addSAlexander Pyhalov 	for (i = 0; i < M_CSETSIZE; i++) {
1602*d2d52addSAlexander Pyhalov 		bmgtab[i] = len;
16037c478bd9Sstevel@tonic-gate 	}
16047c478bd9Sstevel@tonic-gate 
1605*d2d52addSAlexander Pyhalov 	len--;
1606*d2d52addSAlexander Pyhalov 	for (tlen = len, i = 0; i <= len; i++, tlen--) {
1607*d2d52addSAlexander Pyhalov 		bmgtab[*uc++] = tlen;
1608*d2d52addSAlexander Pyhalov 	}
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate 
1611*d2d52addSAlexander Pyhalov /*
1612*d2d52addSAlexander Pyhalov  * BMG search.
1613*d2d52addSAlexander Pyhalov  */
1614*d2d52addSAlexander Pyhalov static char *
1615*d2d52addSAlexander Pyhalov bmgexec(char *str, char *end)
16167c478bd9Sstevel@tonic-gate {
1617*d2d52addSAlexander Pyhalov 	int	t;
1618*d2d52addSAlexander Pyhalov 	char	*k, *s, *p;
16197c478bd9Sstevel@tonic-gate 
1620*d2d52addSAlexander Pyhalov 	k = str + bmglen - 1;
1621*d2d52addSAlexander Pyhalov 	if (bmglen == 1) {
1622*d2d52addSAlexander Pyhalov 		return (memchr(str, bmgpat[0], end - str));
1623*d2d52addSAlexander Pyhalov 	}
1624*d2d52addSAlexander Pyhalov 	for (; ; ) {
1625*d2d52addSAlexander Pyhalov 		/* inner loop, should be most optimized */
1626*d2d52addSAlexander Pyhalov 		while (k < end && (t = bmgtab[(unsigned char)*k]) != 0) {
1627*d2d52addSAlexander Pyhalov 			k += t;
1628*d2d52addSAlexander Pyhalov 		}
1629*d2d52addSAlexander Pyhalov 		if (k >= end) {
1630*d2d52addSAlexander Pyhalov 			return (NULL);
1631*d2d52addSAlexander Pyhalov 		}
1632*d2d52addSAlexander Pyhalov 		for (s = k, p = bmgpat + bmglen - 1; *--s == *--p; ) {
1633*d2d52addSAlexander Pyhalov 			if (p == bmgpat) {
1634*d2d52addSAlexander Pyhalov 				return (s);
1635*d2d52addSAlexander Pyhalov 			}
1636*d2d52addSAlexander Pyhalov 		}
1637*d2d52addSAlexander Pyhalov 		k++;
1638*d2d52addSAlexander Pyhalov 	}
1639*d2d52addSAlexander Pyhalov 	/* NOTREACHED */
16407c478bd9Sstevel@tonic-gate }
1641