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 /*
23d2d52addSAlexander Pyhalov * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
27d2d52addSAlexander Pyhalov /*
28d2d52addSAlexander Pyhalov * grep - pattern matching program - combined grep, egrep, and fgrep.
29d2d52addSAlexander Pyhalov * Based on MKS grep command, with XCU & Solaris mods.
30d2d52addSAlexander Pyhalov */
317c478bd9Sstevel@tonic-gate
32d2d52addSAlexander Pyhalov /*
33d2d52addSAlexander Pyhalov * Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved.
34d2d52addSAlexander Pyhalov *
35d2d52addSAlexander Pyhalov */
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /*
384adc6f15SPeter Tribble * Copyright 2020 Peter Tribble.
39d9241f99SAndrew Stormont * Copyright 2018 RackTop Systems.
40925beec7SYuri Pankov * Copyright 2018 Nexenta Systems, Inc.
4141599e9fSDamian Bogel * Copyright 2013 Damian Bogel. All rights reserved.
422e5ac464SRobert Mustacchi * Copyright 2020 Oxide Computer Company
4341599e9fSDamian Bogel */
4441599e9fSDamian Bogel
457c478bd9Sstevel@tonic-gate #include <string.h>
46d2d52addSAlexander Pyhalov #include <stdlib.h>
47d2d52addSAlexander Pyhalov #include <ctype.h>
48d2d52addSAlexander Pyhalov #include <stdarg.h>
49d2d52addSAlexander Pyhalov #include <regex.h>
50e52fb54bSAlexander Eremin #include <limits.h>
51d2d52addSAlexander Pyhalov #include <sys/types.h>
52d2d52addSAlexander Pyhalov #include <sys/stat.h>
53d2d52addSAlexander Pyhalov #include <fcntl.h>
54d2d52addSAlexander Pyhalov #include <stdio.h>
55d2d52addSAlexander Pyhalov #include <locale.h>
56d2d52addSAlexander Pyhalov #include <wchar.h>
57d2d52addSAlexander Pyhalov #include <errno.h>
58d2d52addSAlexander Pyhalov #include <unistd.h>
59d2d52addSAlexander Pyhalov #include <wctype.h>
60d2d52addSAlexander Pyhalov #include <ftw.h>
61e52fb54bSAlexander Eremin #include <sys/param.h>
628ccd0217SRobert Mustacchi #include <getopt.h>
637c478bd9Sstevel@tonic-gate
6441599e9fSDamian Bogel #define STDIN_FILENAME gettext("(standard input)")
6541599e9fSDamian Bogel
66d2d52addSAlexander Pyhalov #define BSIZE 512 /* Size of block for -b */
67d2d52addSAlexander Pyhalov #define BUFSIZE 8192 /* Input buffer size */
68d2d52addSAlexander Pyhalov #define MAX_DEPTH 1000 /* how deep to recurse */
697c478bd9Sstevel@tonic-gate
70d2d52addSAlexander Pyhalov #define AFTER 1 /* 'After' Context */
71d2d52addSAlexander Pyhalov #define BEFORE 2 /* 'Before' Context */
72d2d52addSAlexander Pyhalov #define CONTEXT (AFTER|BEFORE) /* Full Context */
737c478bd9Sstevel@tonic-gate
74d2d52addSAlexander Pyhalov #define M_CSETSIZE 256 /* singlebyte chars */
75d2d52addSAlexander Pyhalov static int bmglen; /* length of BMG pattern */
76d2d52addSAlexander Pyhalov static char *bmgpat; /* BMG pattern */
77d2d52addSAlexander Pyhalov static int bmgtab[M_CSETSIZE]; /* BMG delta1 table */
78d2d52addSAlexander Pyhalov
79d2d52addSAlexander Pyhalov typedef struct _PATTERN {
80d2d52addSAlexander Pyhalov char *pattern; /* original pattern */
81d2d52addSAlexander Pyhalov struct _PATTERN *next;
82d2d52addSAlexander Pyhalov regex_t re; /* compiled pattern */
83d2d52addSAlexander Pyhalov } PATTERN;
84d2d52addSAlexander Pyhalov
85d2d52addSAlexander Pyhalov static PATTERN *patterns;
86d2d52addSAlexander Pyhalov static char errstr[128]; /* regerror string buffer */
87d2d52addSAlexander Pyhalov static int regflags = 0; /* regcomp options */
88d2d52addSAlexander Pyhalov static int matched = 0; /* return of the grep() */
89d2d52addSAlexander Pyhalov static int errors = 0; /* count of errors */
90d2d52addSAlexander Pyhalov static uchar_t fgrep = 0; /* Invoked as fgrep */
91d2d52addSAlexander Pyhalov static uchar_t egrep = 0; /* Invoked as egrep */
92d2d52addSAlexander Pyhalov static boolean_t nvflag = B_TRUE; /* Print matching lines */
93d2d52addSAlexander Pyhalov static uchar_t cflag; /* Count of matches */
94d2d52addSAlexander Pyhalov static uchar_t iflag; /* Case insensitve matching */
95d2d52addSAlexander Pyhalov static uchar_t Hflag; /* Precede lines by file name */
964adc6f15SPeter Tribble static uchar_t hflag; /* Suppress printing of filename */
97d2d52addSAlexander Pyhalov static uchar_t lflag; /* Print file names of matches */
982e5ac464SRobert Mustacchi static uchar_t Lflag; /* Print file names of non-matches */
99d2d52addSAlexander Pyhalov static uchar_t nflag; /* Precede lines by line number */
100d2d52addSAlexander Pyhalov static uchar_t rflag; /* Search directories recursively */
1014adc6f15SPeter Tribble static uchar_t bflag; /* Precede matches by block number */
102d2d52addSAlexander Pyhalov static uchar_t sflag; /* Suppress file error messages */
103d2d52addSAlexander Pyhalov static uchar_t qflag; /* Suppress standard output */
104d2d52addSAlexander Pyhalov static uchar_t wflag; /* Search for expression as a word */
105d2d52addSAlexander Pyhalov static uchar_t xflag; /* Anchoring */
106d2d52addSAlexander Pyhalov static uchar_t Eflag; /* Egrep or -E flag */
107d2d52addSAlexander Pyhalov static uchar_t Fflag; /* Fgrep or -F flag */
108d2d52addSAlexander Pyhalov static uchar_t Rflag; /* Like rflag, but follow symlinks */
109d2d52addSAlexander Pyhalov static uchar_t outfn; /* Put out file name */
110d2d52addSAlexander Pyhalov static uchar_t conflag; /* show context of matches */
11181dd18d8SRobert Mustacchi static uchar_t oflag; /* Print only matching output */
112d2d52addSAlexander Pyhalov static char *cmdname;
1138ccd0217SRobert Mustacchi static char *stdin_label; /* Optional lable for stdin */
114d2d52addSAlexander Pyhalov
11581dd18d8SRobert Mustacchi static int use_bmg, mblocale;
116d2d52addSAlexander Pyhalov
11781dd18d8SRobert Mustacchi static size_t prntbuflen, conbuflen;
118d2d52addSAlexander Pyhalov static unsigned long conalen, conblen, conmatches;
119d2d52addSAlexander Pyhalov static char *prntbuf, *conbuf;
120d2d52addSAlexander Pyhalov
121d2d52addSAlexander Pyhalov static void addfile(const char *fn);
122d2d52addSAlexander Pyhalov static void addpattern(char *s);
123d2d52addSAlexander Pyhalov static void fixpatterns(void);
124d2d52addSAlexander Pyhalov static void usage(void);
125d2d52addSAlexander Pyhalov static int grep(int, const char *);
126d2d52addSAlexander Pyhalov static void bmgcomp(char *, int);
127d2d52addSAlexander Pyhalov static char *bmgexec(char *, char *);
128e52fb54bSAlexander Eremin static int recursive(const char *, const struct stat *, int, struct FTW *);
129d2d52addSAlexander Pyhalov static void process_path(const char *);
130d2d52addSAlexander Pyhalov static void process_file(const char *, int);
1317c478bd9Sstevel@tonic-gate
132d2d52addSAlexander Pyhalov /*
1338ccd0217SRobert Mustacchi * These are values that we use to return from getopt_long. They start at
1348ccd0217SRobert Mustacchi * SHRT_MAX to avoid any possible conflict with the normal options. These are
1358ccd0217SRobert Mustacchi * used for long options that have no short option equivalent.
1368ccd0217SRobert Mustacchi */
1378ccd0217SRobert Mustacchi enum grep_opts {
1388ccd0217SRobert Mustacchi OPT_LABEL = SHRT_MAX + 1
1398ccd0217SRobert Mustacchi };
1408ccd0217SRobert Mustacchi
1418ccd0217SRobert Mustacchi static struct option grep_options[] = {
1428ccd0217SRobert Mustacchi { "label", required_argument, NULL, OPT_LABEL },
1438ccd0217SRobert Mustacchi { NULL }
1448ccd0217SRobert Mustacchi };
1458ccd0217SRobert Mustacchi
1468ccd0217SRobert Mustacchi /*
147d2d52addSAlexander Pyhalov * mainline for grep
148d2d52addSAlexander Pyhalov */
1497c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)15055f91622Sceastha main(int argc, char **argv)
1517c478bd9Sstevel@tonic-gate {
152d2d52addSAlexander Pyhalov char *ap, *test;
1537c478bd9Sstevel@tonic-gate int c;
154d2d52addSAlexander Pyhalov int fflag = 0;
155d2d52addSAlexander Pyhalov int i, n_pattern = 0, n_file = 0;
156d2d52addSAlexander Pyhalov char **pattern_list = NULL;
157d2d52addSAlexander Pyhalov char **file_list = NULL;
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1607c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
1617c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
1627c478bd9Sstevel@tonic-gate #endif
1637c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1647c478bd9Sstevel@tonic-gate
165d2d52addSAlexander Pyhalov /*
166d2d52addSAlexander Pyhalov * true if this is running on the multibyte locale
167d2d52addSAlexander Pyhalov */
168d2d52addSAlexander Pyhalov mblocale = (MB_CUR_MAX > 1);
169d2d52addSAlexander Pyhalov /*
170d2d52addSAlexander Pyhalov * Skip leading slashes
171d2d52addSAlexander Pyhalov */
172d2d52addSAlexander Pyhalov cmdname = argv[0];
173d2d52addSAlexander Pyhalov if (ap = strrchr(cmdname, '/'))
174d2d52addSAlexander Pyhalov cmdname = ap + 1;
175d2d52addSAlexander Pyhalov
176d2d52addSAlexander Pyhalov ap = cmdname;
177d2d52addSAlexander Pyhalov /*
178d2d52addSAlexander Pyhalov * Detect egrep/fgrep via command name, map to -E and -F options.
179d2d52addSAlexander Pyhalov */
180d2d52addSAlexander Pyhalov if (*ap == 'e' || *ap == 'E') {
181d2d52addSAlexander Pyhalov regflags |= REG_EXTENDED;
182d2d52addSAlexander Pyhalov egrep++;
183d2d52addSAlexander Pyhalov } else {
184d2d52addSAlexander Pyhalov if (*ap == 'f' || *ap == 'F') {
185d2d52addSAlexander Pyhalov fgrep++;
18681dd18d8SRobert Mustacchi regflags |= REG_NOSPEC;
187d2d52addSAlexander Pyhalov }
188d2d52addSAlexander Pyhalov }
189d2d52addSAlexander Pyhalov
190d2d52addSAlexander Pyhalov /* check for non-standard "-line-count" option */
191d2d52addSAlexander Pyhalov for (i = 1; i < argc; i++) {
192d2d52addSAlexander Pyhalov if (strcmp(argv[i], "--") == 0)
193d2d52addSAlexander Pyhalov break;
194d2d52addSAlexander Pyhalov
195d2d52addSAlexander Pyhalov /* isdigit() check prevents negative arguments */
196d2d52addSAlexander Pyhalov if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
197d2d52addSAlexander Pyhalov if (strlen(&argv[i][1]) !=
198d2d52addSAlexander Pyhalov strspn(&argv[i][1], "0123456789")) {
199d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
200d2d52addSAlexander Pyhalov "%s: Bad number flag\n"), argv[0]);
201d2d52addSAlexander Pyhalov usage();
202d2d52addSAlexander Pyhalov }
203d2d52addSAlexander Pyhalov
204d2d52addSAlexander Pyhalov errno = 0;
205d2d52addSAlexander Pyhalov conalen = conblen = strtoul(&argv[i][1], (char **)NULL,
206d2d52addSAlexander Pyhalov 10);
207d2d52addSAlexander Pyhalov
208d2d52addSAlexander Pyhalov if (errno != 0 || conalen >= ULONG_MAX) {
209d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
210d2d52addSAlexander Pyhalov "%s: Bad context argument\n"), argv[0]);
211d2d52addSAlexander Pyhalov } else if (conalen)
212d2d52addSAlexander Pyhalov conflag = CONTEXT;
213d2d52addSAlexander Pyhalov
214d2d52addSAlexander Pyhalov while (i < argc) {
215d2d52addSAlexander Pyhalov argv[i] = argv[i + 1];
216d2d52addSAlexander Pyhalov i++;
217d2d52addSAlexander Pyhalov }
218d2d52addSAlexander Pyhalov argc--;
219d2d52addSAlexander Pyhalov }
220d2d52addSAlexander Pyhalov }
221d2d52addSAlexander Pyhalov
22281dd18d8SRobert Mustacchi while ((c = getopt_long(argc, argv, "+vwchHilLnrbse:f:qxEFIRA:B:C:o",
2238ccd0217SRobert Mustacchi grep_options, NULL)) != EOF) {
224d2d52addSAlexander Pyhalov unsigned long tval;
2257c478bd9Sstevel@tonic-gate switch (c) {
226d2d52addSAlexander Pyhalov case 'v': /* POSIX: negate matches */
227d2d52addSAlexander Pyhalov nvflag = B_FALSE;
228d2d52addSAlexander Pyhalov break;
229d2d52addSAlexander Pyhalov
230d2d52addSAlexander Pyhalov case 'c': /* POSIX: write count */
231d2d52addSAlexander Pyhalov cflag++;
232d2d52addSAlexander Pyhalov break;
233d2d52addSAlexander Pyhalov
234d2d52addSAlexander Pyhalov case 'i': /* POSIX: ignore case */
235d2d52addSAlexander Pyhalov iflag++;
236d2d52addSAlexander Pyhalov regflags |= REG_ICASE;
237d2d52addSAlexander Pyhalov break;
238d2d52addSAlexander Pyhalov
2392e5ac464SRobert Mustacchi /*
2402e5ac464SRobert Mustacchi * The last of -l and -L are honored.
2412e5ac464SRobert Mustacchi */
242d2d52addSAlexander Pyhalov case 'l': /* POSIX: Write filenames only */
243d2d52addSAlexander Pyhalov lflag++;
2442e5ac464SRobert Mustacchi Lflag = 0;
2452e5ac464SRobert Mustacchi break;
2462e5ac464SRobert Mustacchi
2472e5ac464SRobert Mustacchi case 'L': /* Write non-matching filenames */
2482e5ac464SRobert Mustacchi Lflag++;
2492e5ac464SRobert Mustacchi lflag = 0;
250d2d52addSAlexander Pyhalov break;
251d2d52addSAlexander Pyhalov
252d2d52addSAlexander Pyhalov case 'n': /* POSIX: Write line numbers */
253d2d52addSAlexander Pyhalov nflag++;
254d2d52addSAlexander Pyhalov break;
255d2d52addSAlexander Pyhalov
256d2d52addSAlexander Pyhalov case 'r': /* Solaris: search recursively */
257d2d52addSAlexander Pyhalov rflag++;
258d2d52addSAlexander Pyhalov break;
259d2d52addSAlexander Pyhalov
260d2d52addSAlexander Pyhalov case 'b': /* Solaris: Write file block numbers */
261d2d52addSAlexander Pyhalov bflag++;
262d2d52addSAlexander Pyhalov break;
263d2d52addSAlexander Pyhalov
264d2d52addSAlexander Pyhalov case 's': /* POSIX: No error msgs for files */
265d2d52addSAlexander Pyhalov sflag++;
266d2d52addSAlexander Pyhalov break;
267d2d52addSAlexander Pyhalov
268d2d52addSAlexander Pyhalov case 'e': /* POSIX: pattern list */
269d2d52addSAlexander Pyhalov n_pattern++;
270d2d52addSAlexander Pyhalov pattern_list = realloc(pattern_list,
271d2d52addSAlexander Pyhalov sizeof (char *) * n_pattern);
272d2d52addSAlexander Pyhalov if (pattern_list == NULL) {
273d2d52addSAlexander Pyhalov (void) fprintf(stderr,
274d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
275d2d52addSAlexander Pyhalov cmdname);
276d2d52addSAlexander Pyhalov exit(2);
277d2d52addSAlexander Pyhalov }
278d2d52addSAlexander Pyhalov *(pattern_list + n_pattern - 1) = optarg;
279d2d52addSAlexander Pyhalov break;
280d2d52addSAlexander Pyhalov
281d2d52addSAlexander Pyhalov case 'f': /* POSIX: pattern file */
282d2d52addSAlexander Pyhalov fflag = 1;
283d2d52addSAlexander Pyhalov n_file++;
284d2d52addSAlexander Pyhalov file_list = realloc(file_list,
285d2d52addSAlexander Pyhalov sizeof (char *) * n_file);
286d2d52addSAlexander Pyhalov if (file_list == NULL) {
287d2d52addSAlexander Pyhalov (void) fprintf(stderr,
288d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
289d2d52addSAlexander Pyhalov cmdname);
290d2d52addSAlexander Pyhalov exit(2);
291d2d52addSAlexander Pyhalov }
292d2d52addSAlexander Pyhalov *(file_list + n_file - 1) = optarg;
293d2d52addSAlexander Pyhalov break;
294d2d52addSAlexander Pyhalov
29541599e9fSDamian Bogel /* based on options order h or H is set as in GNU grep */
2964adc6f15SPeter Tribble case 'h': /* Solaris: suppress printing of file name */
297d2d52addSAlexander Pyhalov hflag = 1;
298d2d52addSAlexander Pyhalov Hflag = 0;
29941599e9fSDamian Bogel break;
3004adc6f15SPeter Tribble /* Solaris: precede every match with file name */
30141599e9fSDamian Bogel case 'H':
302d2d52addSAlexander Pyhalov Hflag = 1;
303d2d52addSAlexander Pyhalov hflag = 0;
3047c478bd9Sstevel@tonic-gate break;
305d2d52addSAlexander Pyhalov
3063ed621bcSAlexander Eremin case 'q': /* POSIX: quiet: status only */
3073ed621bcSAlexander Eremin qflag++;
3083ed621bcSAlexander Eremin break;
309d2d52addSAlexander Pyhalov
310d2d52addSAlexander Pyhalov case 'w': /* Solaris: treat pattern as word */
3117c478bd9Sstevel@tonic-gate wflag++;
3127c478bd9Sstevel@tonic-gate break;
3137c478bd9Sstevel@tonic-gate
314d2d52addSAlexander Pyhalov case 'x': /* POSIX: full line matches */
315d2d52addSAlexander Pyhalov xflag++;
316d2d52addSAlexander Pyhalov break;
317d2d52addSAlexander Pyhalov
318d2d52addSAlexander Pyhalov case 'E': /* POSIX: Extended RE's */
319d2d52addSAlexander Pyhalov regflags |= REG_EXTENDED;
320d2d52addSAlexander Pyhalov Eflag++;
321d2d52addSAlexander Pyhalov break;
322d2d52addSAlexander Pyhalov
323d2d52addSAlexander Pyhalov case 'F': /* POSIX: strings, not RE's */
324d2d52addSAlexander Pyhalov Fflag++;
32581dd18d8SRobert Mustacchi regflags |= REG_NOSPEC;
326d2d52addSAlexander Pyhalov break;
327d2d52addSAlexander Pyhalov
328d2d52addSAlexander Pyhalov case 'R': /* Solaris: like rflag, but follow symlinks */
329d2d52addSAlexander Pyhalov Rflag++;
330d2d52addSAlexander Pyhalov rflag++;
331d2d52addSAlexander Pyhalov break;
332d2d52addSAlexander Pyhalov
333d2d52addSAlexander Pyhalov case 'A': /* print N lines after each match */
334d2d52addSAlexander Pyhalov errno = 0;
335d2d52addSAlexander Pyhalov conalen = strtoul(optarg, &test, 10);
336d2d52addSAlexander Pyhalov /* *test will be non-null if optarg is negative */
337d2d52addSAlexander Pyhalov if (errno != 0 || *test != '\0' ||
338d2d52addSAlexander Pyhalov conalen >= ULONG_MAX) {
339d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
340d2d52addSAlexander Pyhalov "%s: Bad context argument: %s\n"),
341d2d52addSAlexander Pyhalov argv[0], optarg);
3427c478bd9Sstevel@tonic-gate exit(2);
3437c478bd9Sstevel@tonic-gate }
344d2d52addSAlexander Pyhalov if (conalen)
345d2d52addSAlexander Pyhalov conflag |= AFTER;
3467c478bd9Sstevel@tonic-gate else
347d2d52addSAlexander Pyhalov conflag &= ~AFTER;
348d2d52addSAlexander Pyhalov break;
349d2d52addSAlexander Pyhalov case 'B': /* print N lines before each match */
350d2d52addSAlexander Pyhalov errno = 0;
351d2d52addSAlexander Pyhalov conblen = strtoul(optarg, &test, 10);
352d2d52addSAlexander Pyhalov /* *test will be non-null if optarg is negative */
353d2d52addSAlexander Pyhalov if (errno != 0 || *test != '\0' ||
354d2d52addSAlexander Pyhalov conblen >= ULONG_MAX) {
355d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
356d2d52addSAlexander Pyhalov "%s: Bad context argument: %s\n"),
357d2d52addSAlexander Pyhalov argv[0], optarg);
358d2d52addSAlexander Pyhalov exit(2);
359d2d52addSAlexander Pyhalov }
360d2d52addSAlexander Pyhalov if (conblen)
361d2d52addSAlexander Pyhalov conflag |= BEFORE;
362d2d52addSAlexander Pyhalov else
363d2d52addSAlexander Pyhalov conflag &= ~BEFORE;
364d2d52addSAlexander Pyhalov break;
365d2d52addSAlexander Pyhalov case 'C': /* print N lines around each match */
366d2d52addSAlexander Pyhalov errno = 0;
367d2d52addSAlexander Pyhalov tval = strtoul(optarg, &test, 10);
368d2d52addSAlexander Pyhalov /* *test will be non-null if optarg is negative */
369d2d52addSAlexander Pyhalov if (errno != 0 || *test != '\0' || tval >= ULONG_MAX) {
370d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
371d2d52addSAlexander Pyhalov "%s: Bad context argument: %s\n"),
372d2d52addSAlexander Pyhalov argv[0], optarg);
373d2d52addSAlexander Pyhalov exit(2);
374d2d52addSAlexander Pyhalov }
375d2d52addSAlexander Pyhalov if (tval) {
376d2d52addSAlexander Pyhalov if ((conflag & BEFORE) == 0)
377d2d52addSAlexander Pyhalov conblen = tval;
378d2d52addSAlexander Pyhalov if ((conflag & AFTER) == 0)
379d2d52addSAlexander Pyhalov conalen = tval;
380d2d52addSAlexander Pyhalov conflag = CONTEXT;
381d2d52addSAlexander Pyhalov }
382d2d52addSAlexander Pyhalov break;
3837c478bd9Sstevel@tonic-gate
3848ccd0217SRobert Mustacchi case OPT_LABEL:
3858ccd0217SRobert Mustacchi stdin_label = optarg;
3868ccd0217SRobert Mustacchi break;
3878ccd0217SRobert Mustacchi
38881dd18d8SRobert Mustacchi case 'o':
38981dd18d8SRobert Mustacchi oflag++;
39081dd18d8SRobert Mustacchi break;
39181dd18d8SRobert Mustacchi
392d2d52addSAlexander Pyhalov default:
393d2d52addSAlexander Pyhalov usage();
394d2d52addSAlexander Pyhalov }
395d2d52addSAlexander Pyhalov }
396d2d52addSAlexander Pyhalov /*
397d2d52addSAlexander Pyhalov * If we're invoked as egrep or fgrep we need to do some checks
398d2d52addSAlexander Pyhalov */
399d2d52addSAlexander Pyhalov
400d2d52addSAlexander Pyhalov if (egrep || fgrep) {
401d2d52addSAlexander Pyhalov /*
402d2d52addSAlexander Pyhalov * Use of -E or -F with egrep or fgrep is illegal
403d2d52addSAlexander Pyhalov */
404d2d52addSAlexander Pyhalov if (Eflag || Fflag)
405d2d52addSAlexander Pyhalov usage();
406d2d52addSAlexander Pyhalov /*
407d2d52addSAlexander Pyhalov * Don't allow use of wflag with egrep / fgrep
408d2d52addSAlexander Pyhalov */
409d2d52addSAlexander Pyhalov if (wflag)
410d2d52addSAlexander Pyhalov usage();
411d2d52addSAlexander Pyhalov /*
412d2d52addSAlexander Pyhalov * For Solaris the -s flag is equivalent to XCU -q
413d2d52addSAlexander Pyhalov */
414d2d52addSAlexander Pyhalov if (sflag)
415d2d52addSAlexander Pyhalov qflag++;
416d2d52addSAlexander Pyhalov /*
417d2d52addSAlexander Pyhalov * done with above checks - set the appropriate flags
418d2d52addSAlexander Pyhalov */
419d2d52addSAlexander Pyhalov if (egrep)
420d2d52addSAlexander Pyhalov Eflag++;
421d2d52addSAlexander Pyhalov else /* Else fgrep */
422d2d52addSAlexander Pyhalov Fflag++;
423d2d52addSAlexander Pyhalov }
424d2d52addSAlexander Pyhalov
425d2d52addSAlexander Pyhalov if (wflag && (Eflag || Fflag)) {
426d2d52addSAlexander Pyhalov /*
427d2d52addSAlexander Pyhalov * -w cannot be specified with grep -F
428d2d52addSAlexander Pyhalov */
429d2d52addSAlexander Pyhalov usage();
430d2d52addSAlexander Pyhalov }
431d2d52addSAlexander Pyhalov
432d2d52addSAlexander Pyhalov /*
433d2d52addSAlexander Pyhalov * -E and -F flags are mutually exclusive - check for this
434d2d52addSAlexander Pyhalov */
435d2d52addSAlexander Pyhalov if (Eflag && Fflag)
436d2d52addSAlexander Pyhalov usage();
437d2d52addSAlexander Pyhalov
438d2d52addSAlexander Pyhalov /*
43981dd18d8SRobert Mustacchi * -l or -L overrides -H like in GNU grep. It also overrides -o.
440d2d52addSAlexander Pyhalov */
44181dd18d8SRobert Mustacchi if (lflag || Lflag) {
442d2d52addSAlexander Pyhalov Hflag = 0;
44381dd18d8SRobert Mustacchi oflag = 0;
44481dd18d8SRobert Mustacchi }
445d2d52addSAlexander Pyhalov
446d2d52addSAlexander Pyhalov /*
447d2d52addSAlexander Pyhalov * -c, -l and -q flags are mutually exclusive
448d2d52addSAlexander Pyhalov * We have -c override -l like in Solaris.
449d2d52addSAlexander Pyhalov * -q overrides -l & -c programmatically in grep() function.
45081dd18d8SRobert Mustacchi * -c overrides -o in GNU grep, we honor that.
451d2d52addSAlexander Pyhalov */
45281dd18d8SRobert Mustacchi if (cflag) {
453d2d52addSAlexander Pyhalov lflag = 0;
4542e5ac464SRobert Mustacchi Lflag = 0;
45581dd18d8SRobert Mustacchi oflag = 0;
45681dd18d8SRobert Mustacchi }
45781dd18d8SRobert Mustacchi
45881dd18d8SRobert Mustacchi /*
45981dd18d8SRobert Mustacchi * If -o is set then we ignore all context related options, like other
46081dd18d8SRobert Mustacchi * greps.
46181dd18d8SRobert Mustacchi */
46281dd18d8SRobert Mustacchi if (oflag) {
46381dd18d8SRobert Mustacchi conflag = 0;
46481dd18d8SRobert Mustacchi }
46581dd18d8SRobert Mustacchi
46681dd18d8SRobert Mustacchi /*
46781dd18d8SRobert Mustacchi * These flags are a semantic mess with no clear answers as to their
46881dd18d8SRobert Mustacchi * behvaior. Based on some experimentation GNU grep will exit zero if a
46981dd18d8SRobert Mustacchi * non-match is present, but never print anything. BSD grep seems to
47081dd18d8SRobert Mustacchi * exit 1 and not print anything, even if there would have been a match.
47181dd18d8SRobert Mustacchi * Also, you probably don't want to ask about what happens with grep -x
47281dd18d8SRobert Mustacchi * -o -v, some implementations seem to just ignore -v.
47381dd18d8SRobert Mustacchi */
47481dd18d8SRobert Mustacchi if (oflag && !nvflag) {
47581dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext("%s: the combination of -v and "
47681dd18d8SRobert Mustacchi "-o is not supported currently\n"), argv[0]);
47781dd18d8SRobert Mustacchi exit(2);
4782e5ac464SRobert Mustacchi }
479d2d52addSAlexander Pyhalov
480d2d52addSAlexander Pyhalov argv += optind - 1;
481d2d52addSAlexander Pyhalov argc -= optind - 1;
482d2d52addSAlexander Pyhalov
483d2d52addSAlexander Pyhalov /*
484d2d52addSAlexander Pyhalov * Now handling -e and -f option
485d2d52addSAlexander Pyhalov */
486d2d52addSAlexander Pyhalov if (pattern_list) {
487d2d52addSAlexander Pyhalov for (i = 0; i < n_pattern; i++) {
488d2d52addSAlexander Pyhalov addpattern(pattern_list[i]);
489d2d52addSAlexander Pyhalov }
490d2d52addSAlexander Pyhalov free(pattern_list);
491d2d52addSAlexander Pyhalov }
492d2d52addSAlexander Pyhalov if (file_list) {
493d2d52addSAlexander Pyhalov for (i = 0; i < n_file; i++) {
494d2d52addSAlexander Pyhalov addfile(file_list[i]);
495d2d52addSAlexander Pyhalov }
496d2d52addSAlexander Pyhalov free(file_list);
497d2d52addSAlexander Pyhalov }
498d2d52addSAlexander Pyhalov
499d2d52addSAlexander Pyhalov /*
500d2d52addSAlexander Pyhalov * No -e or -f? Make sure there is one more arg, use it as the pattern.
501d2d52addSAlexander Pyhalov */
502d2d52addSAlexander Pyhalov if (patterns == NULL && !fflag) {
503d2d52addSAlexander Pyhalov if (argc < 2)
504d2d52addSAlexander Pyhalov usage();
505d2d52addSAlexander Pyhalov addpattern(argv[1]);
506d2d52addSAlexander Pyhalov argc--;
507d2d52addSAlexander Pyhalov argv++;
508d2d52addSAlexander Pyhalov }
509d2d52addSAlexander Pyhalov
510d2d52addSAlexander Pyhalov /*
511d2d52addSAlexander Pyhalov * Compile Patterns and also decide if BMG can be used
512d2d52addSAlexander Pyhalov */
513d2d52addSAlexander Pyhalov fixpatterns();
514d2d52addSAlexander Pyhalov
5158ccd0217SRobert Mustacchi if (stdin_label == NULL) {
5168ccd0217SRobert Mustacchi stdin_label = STDIN_FILENAME;
5178ccd0217SRobert Mustacchi }
5188ccd0217SRobert Mustacchi
519d2d52addSAlexander Pyhalov /* Process all files: stdin, or rest of arg list */
520d2d52addSAlexander Pyhalov if (argc < 2) {
5218ccd0217SRobert Mustacchi matched = grep(0, stdin_label);
522d2d52addSAlexander Pyhalov } else {
523d2d52addSAlexander Pyhalov if (Hflag || (argc > 2 && hflag == 0))
524d2d52addSAlexander Pyhalov outfn = 1; /* Print filename on match line */
525d2d52addSAlexander Pyhalov for (argv++; *argv != NULL; argv++) {
526d2d52addSAlexander Pyhalov process_path(*argv);
527d2d52addSAlexander Pyhalov }
528d2d52addSAlexander Pyhalov }
529d2d52addSAlexander Pyhalov /*
530d2d52addSAlexander Pyhalov * Return() here is used instead of exit
531d2d52addSAlexander Pyhalov */
532d2d52addSAlexander Pyhalov
533d2d52addSAlexander Pyhalov (void) fflush(stdout);
534d2d52addSAlexander Pyhalov
535d2d52addSAlexander Pyhalov if (errors)
536d2d52addSAlexander Pyhalov return (2);
537d2d52addSAlexander Pyhalov return (matched ? 0 : 1);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate static void
process_path(const char * path)541d2d52addSAlexander Pyhalov process_path(const char *path)
542e52fb54bSAlexander Eremin {
543e52fb54bSAlexander Eremin struct stat st;
544e52fb54bSAlexander Eremin int walkflags = FTW_CHDIR;
545e52fb54bSAlexander Eremin char *buf = NULL;
546e52fb54bSAlexander Eremin
547e52fb54bSAlexander Eremin if (rflag) {
548e52fb54bSAlexander Eremin if (stat(path, &st) != -1 &&
549e52fb54bSAlexander Eremin (st.st_mode & S_IFMT) == S_IFDIR) {
5504adc6f15SPeter Tribble if (!hflag)
5514adc6f15SPeter Tribble outfn = 1; /* Print filename unless -h */
552e52fb54bSAlexander Eremin
553e52fb54bSAlexander Eremin /*
554e52fb54bSAlexander Eremin * Add trailing slash if arg
555e52fb54bSAlexander Eremin * is directory, to resolve symlinks.
556e52fb54bSAlexander Eremin */
557e52fb54bSAlexander Eremin if (path[strlen(path) - 1] != '/') {
558e52fb54bSAlexander Eremin (void) asprintf(&buf, "%s/", path);
559e52fb54bSAlexander Eremin if (buf != NULL)
560e52fb54bSAlexander Eremin path = buf;
561e52fb54bSAlexander Eremin }
562e52fb54bSAlexander Eremin
563e52fb54bSAlexander Eremin /*
564e52fb54bSAlexander Eremin * Search through subdirs if path is directory.
565e52fb54bSAlexander Eremin * Don't follow symlinks if Rflag is not set.
566e52fb54bSAlexander Eremin */
567e52fb54bSAlexander Eremin if (!Rflag)
568e52fb54bSAlexander Eremin walkflags |= FTW_PHYS;
569e52fb54bSAlexander Eremin
570e52fb54bSAlexander Eremin if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) {
571e52fb54bSAlexander Eremin if (!sflag)
572d2d52addSAlexander Pyhalov (void) fprintf(stderr,
573d2d52addSAlexander Pyhalov gettext("%s: can't open \"%s\"\n"),
574d2d52addSAlexander Pyhalov cmdname, path);
575d2d52addSAlexander Pyhalov errors = 1;
576e52fb54bSAlexander Eremin }
577e52fb54bSAlexander Eremin return;
578e52fb54bSAlexander Eremin }
579e52fb54bSAlexander Eremin }
580d2d52addSAlexander Pyhalov process_file(path, 0);
581e52fb54bSAlexander Eremin }
582e52fb54bSAlexander Eremin
583d2d52addSAlexander Pyhalov /*
584d2d52addSAlexander Pyhalov * Read and process all files in directory recursively.
585d2d52addSAlexander Pyhalov */
586e52fb54bSAlexander Eremin static int
recursive(const char * name,const struct stat * statp,int info,struct FTW * ftw)587e52fb54bSAlexander Eremin recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw)
588e52fb54bSAlexander Eremin {
589e52fb54bSAlexander Eremin /*
590d2d52addSAlexander Pyhalov * Process files and follow symlinks if Rflag set.
591e52fb54bSAlexander Eremin */
592e52fb54bSAlexander Eremin if (info != FTW_F) {
593d2d52addSAlexander Pyhalov /* Report broken symlinks and unreadable files */
594e52fb54bSAlexander Eremin if (!sflag &&
595e52fb54bSAlexander Eremin (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
596d2d52addSAlexander Pyhalov (void) fprintf(stderr,
597d2d52addSAlexander Pyhalov gettext("%s: can't open \"%s\"\n"), cmdname, name);
598e52fb54bSAlexander Eremin }
599e52fb54bSAlexander Eremin return (0);
600e52fb54bSAlexander Eremin }
601e52fb54bSAlexander Eremin
602d2d52addSAlexander Pyhalov
603d2d52addSAlexander Pyhalov /* Skip devices and pipes if Rflag is not set */
604e52fb54bSAlexander Eremin if (!Rflag && !S_ISREG(statp->st_mode))
605e52fb54bSAlexander Eremin return (0);
606d2d52addSAlexander Pyhalov /* Pass offset to relative name from FTW_CHDIR */
607d2d52addSAlexander Pyhalov process_file(name, ftw->base);
608e52fb54bSAlexander Eremin return (0);
609e52fb54bSAlexander Eremin }
610e52fb54bSAlexander Eremin
611d2d52addSAlexander Pyhalov /*
612d2d52addSAlexander Pyhalov * Opens file and call grep function.
613d2d52addSAlexander Pyhalov */
614e52fb54bSAlexander Eremin static void
process_file(const char * name,int base)615d2d52addSAlexander Pyhalov process_file(const char *name, int base)
6167c478bd9Sstevel@tonic-gate {
617d2d52addSAlexander Pyhalov int fd;
6187c478bd9Sstevel@tonic-gate
619d2d52addSAlexander Pyhalov if ((fd = open(name + base, O_RDONLY)) == -1) {
620d2d52addSAlexander Pyhalov errors = 1;
621d2d52addSAlexander Pyhalov if (!sflag) /* Silent mode */
622d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
623d2d52addSAlexander Pyhalov "%s: can't open \"%s\"\n"),
624d2d52addSAlexander Pyhalov cmdname, name);
625d2d52addSAlexander Pyhalov return;
626d2d52addSAlexander Pyhalov }
627d2d52addSAlexander Pyhalov matched |= grep(fd, name);
628d2d52addSAlexander Pyhalov (void) close(fd);
629d2d52addSAlexander Pyhalov
630d2d52addSAlexander Pyhalov if (ferror(stdout)) {
631d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
632d2d52addSAlexander Pyhalov "%s: error writing to stdout\n"),
633d2d52addSAlexander Pyhalov cmdname);
634d2d52addSAlexander Pyhalov (void) fflush(stdout);
635d2d52addSAlexander Pyhalov exit(2);
636d2d52addSAlexander Pyhalov }
637d2d52addSAlexander Pyhalov
638d2d52addSAlexander Pyhalov }
639d2d52addSAlexander Pyhalov
640d2d52addSAlexander Pyhalov /*
641d2d52addSAlexander Pyhalov * Add a file of strings to the pattern list.
642d2d52addSAlexander Pyhalov */
643d2d52addSAlexander Pyhalov static void
addfile(const char * fn)644d2d52addSAlexander Pyhalov addfile(const char *fn)
645d2d52addSAlexander Pyhalov {
646d2d52addSAlexander Pyhalov FILE *fp;
647d2d52addSAlexander Pyhalov char *inbuf;
648d2d52addSAlexander Pyhalov char *bufp;
649d2d52addSAlexander Pyhalov size_t bufsiz, buflen, bufused;
650d2d52addSAlexander Pyhalov
651d2d52addSAlexander Pyhalov /*
652d2d52addSAlexander Pyhalov * Open the pattern file
653d2d52addSAlexander Pyhalov */
654d2d52addSAlexander Pyhalov if ((fp = fopen(fn, "r")) == NULL) {
655d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: can't open \"%s\"\n"),
656d2d52addSAlexander Pyhalov cmdname, fn);
657d2d52addSAlexander Pyhalov exit(2);
658d2d52addSAlexander Pyhalov }
659d2d52addSAlexander Pyhalov bufsiz = BUFSIZE;
660d2d52addSAlexander Pyhalov if ((inbuf = malloc(bufsiz)) == NULL) {
661d2d52addSAlexander Pyhalov (void) fprintf(stderr,
662d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), cmdname);
663d2d52addSAlexander Pyhalov exit(2);
664d2d52addSAlexander Pyhalov }
665d2d52addSAlexander Pyhalov bufp = inbuf;
666d2d52addSAlexander Pyhalov bufused = 0;
667d2d52addSAlexander Pyhalov /*
668d2d52addSAlexander Pyhalov * Read in the file, reallocing as we need more memory
669d2d52addSAlexander Pyhalov */
670d2d52addSAlexander Pyhalov while (fgets(bufp, bufsiz - bufused, fp) != NULL) {
671d2d52addSAlexander Pyhalov buflen = strlen(bufp);
672d2d52addSAlexander Pyhalov bufused += buflen;
673d2d52addSAlexander Pyhalov if (bufused + 1 == bufsiz && bufp[buflen - 1] != '\n') {
674d2d52addSAlexander Pyhalov /*
675d2d52addSAlexander Pyhalov * if this line does not fit to the buffer,
676d2d52addSAlexander Pyhalov * realloc larger buffer
677d2d52addSAlexander Pyhalov */
678d2d52addSAlexander Pyhalov bufsiz += BUFSIZE;
679d2d52addSAlexander Pyhalov if ((inbuf = realloc(inbuf, bufsiz)) == NULL) {
680d2d52addSAlexander Pyhalov (void) fprintf(stderr,
681d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
682d2d52addSAlexander Pyhalov cmdname);
683d2d52addSAlexander Pyhalov exit(2);
684d2d52addSAlexander Pyhalov }
685d2d52addSAlexander Pyhalov bufp = inbuf + bufused;
686d2d52addSAlexander Pyhalov continue;
687d2d52addSAlexander Pyhalov }
688d2d52addSAlexander Pyhalov if (bufp[buflen - 1] == '\n') {
689d2d52addSAlexander Pyhalov bufp[--buflen] = '\0';
690d2d52addSAlexander Pyhalov }
691d2d52addSAlexander Pyhalov addpattern(inbuf);
692d2d52addSAlexander Pyhalov
693d2d52addSAlexander Pyhalov bufp = inbuf;
694d2d52addSAlexander Pyhalov bufused = 0;
695d2d52addSAlexander Pyhalov }
696d2d52addSAlexander Pyhalov free(inbuf);
697d2d52addSAlexander Pyhalov free(prntbuf);
698d2d52addSAlexander Pyhalov free(conbuf);
699d2d52addSAlexander Pyhalov (void) fclose(fp);
700d2d52addSAlexander Pyhalov }
701d2d52addSAlexander Pyhalov
702d2d52addSAlexander Pyhalov /*
703d2d52addSAlexander Pyhalov * Add a string to the pattern list.
704d2d52addSAlexander Pyhalov */
705d2d52addSAlexander Pyhalov static void
addpattern(char * s)706d2d52addSAlexander Pyhalov addpattern(char *s)
707d2d52addSAlexander Pyhalov {
708d2d52addSAlexander Pyhalov PATTERN *pp;
709d2d52addSAlexander Pyhalov char *wordbuf;
710d2d52addSAlexander Pyhalov char *np;
711d2d52addSAlexander Pyhalov
712d2d52addSAlexander Pyhalov for (; ; ) {
713d2d52addSAlexander Pyhalov np = strchr(s, '\n');
714d2d52addSAlexander Pyhalov if (np != NULL)
715d2d52addSAlexander Pyhalov *np = '\0';
716d2d52addSAlexander Pyhalov if ((pp = malloc(sizeof (PATTERN))) == NULL) {
717d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
718d2d52addSAlexander Pyhalov "%s: out of memory\n"),
719d2d52addSAlexander Pyhalov cmdname);
720d2d52addSAlexander Pyhalov exit(2);
721d2d52addSAlexander Pyhalov }
722d2d52addSAlexander Pyhalov if (wflag) {
723d2d52addSAlexander Pyhalov /*
724d2d52addSAlexander Pyhalov * Solaris wflag support: Add '<' '>' to pattern to
725d2d52addSAlexander Pyhalov * select it as a word. Doesn't make sense with -F
726d2d52addSAlexander Pyhalov * but we're Libertarian.
727d2d52addSAlexander Pyhalov */
728d2d52addSAlexander Pyhalov size_t slen, wordlen;
729d2d52addSAlexander Pyhalov
730d2d52addSAlexander Pyhalov slen = strlen(s);
731d2d52addSAlexander Pyhalov wordlen = slen + 5; /* '\\' '<' s '\\' '>' '\0' */
732d2d52addSAlexander Pyhalov if ((wordbuf = malloc(wordlen)) == NULL) {
733d2d52addSAlexander Pyhalov (void) fprintf(stderr,
734d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
735d2d52addSAlexander Pyhalov cmdname);
736d2d52addSAlexander Pyhalov exit(2);
737d2d52addSAlexander Pyhalov }
738d2d52addSAlexander Pyhalov (void) strcpy(wordbuf, "\\<");
739d2d52addSAlexander Pyhalov (void) strcpy(wordbuf + 2, s);
740d2d52addSAlexander Pyhalov (void) strcpy(wordbuf + 2 + slen, "\\>");
741d2d52addSAlexander Pyhalov } else {
742d2d52addSAlexander Pyhalov if ((wordbuf = strdup(s)) == NULL) {
743d2d52addSAlexander Pyhalov (void) fprintf(stderr,
744d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
745d2d52addSAlexander Pyhalov cmdname);
746d2d52addSAlexander Pyhalov exit(2);
747d2d52addSAlexander Pyhalov }
748d2d52addSAlexander Pyhalov }
749d2d52addSAlexander Pyhalov pp->pattern = wordbuf;
750d2d52addSAlexander Pyhalov pp->next = patterns;
751d2d52addSAlexander Pyhalov patterns = pp;
752d2d52addSAlexander Pyhalov if (np == NULL)
753d2d52addSAlexander Pyhalov break;
754d2d52addSAlexander Pyhalov s = np + 1;
755d2d52addSAlexander Pyhalov }
756d2d52addSAlexander Pyhalov }
757d2d52addSAlexander Pyhalov
758d2d52addSAlexander Pyhalov /*
759*dbe930bfSRobert Mustacchi * Check if a given grep pattern that is being used with egrep or grep can be
760*dbe930bfSRobert Mustacchi * considered 'simple'. That is there are no characters that would be treated
761*dbe930bfSRobert Mustacchi * differently from fgrep. In this particular case, we're a little bit
762*dbe930bfSRobert Mustacchi * conservative and look for characters that are:
763*dbe930bfSRobert Mustacchi *
764*dbe930bfSRobert Mustacchi * o 7-bit ASCII
765*dbe930bfSRobert Mustacchi * o Letters
766*dbe930bfSRobert Mustacchi * o Numbers
767*dbe930bfSRobert Mustacchi * o Meta-characters not used in BREs/EREs: !, @, #, /, -, _, <, >, =
768*dbe930bfSRobert Mustacchi *
769*dbe930bfSRobert Mustacchi * This can certianly be made more complex and less restrictive with additional
770*dbe930bfSRobert Mustacchi * testing.
771*dbe930bfSRobert Mustacchi */
772*dbe930bfSRobert Mustacchi static boolean_t
simple_pattern(const char * str)773*dbe930bfSRobert Mustacchi simple_pattern(const char *str)
774*dbe930bfSRobert Mustacchi {
775*dbe930bfSRobert Mustacchi for (; *str != '\0'; str++) {
776*dbe930bfSRobert Mustacchi if (!isascii(*str)) {
777*dbe930bfSRobert Mustacchi return (B_FALSE);
778*dbe930bfSRobert Mustacchi }
779*dbe930bfSRobert Mustacchi
780*dbe930bfSRobert Mustacchi if (isalnum(*str)) {
781*dbe930bfSRobert Mustacchi continue;
782*dbe930bfSRobert Mustacchi }
783*dbe930bfSRobert Mustacchi
784*dbe930bfSRobert Mustacchi switch (*str) {
785*dbe930bfSRobert Mustacchi case '!':
786*dbe930bfSRobert Mustacchi case '@':
787*dbe930bfSRobert Mustacchi case '#':
788*dbe930bfSRobert Mustacchi case '/':
789*dbe930bfSRobert Mustacchi case '-':
790*dbe930bfSRobert Mustacchi case '_':
791*dbe930bfSRobert Mustacchi case '<':
792*dbe930bfSRobert Mustacchi case '>':
793*dbe930bfSRobert Mustacchi case '=':
794*dbe930bfSRobert Mustacchi continue;
795*dbe930bfSRobert Mustacchi default:
796*dbe930bfSRobert Mustacchi return (B_FALSE);
797*dbe930bfSRobert Mustacchi }
798*dbe930bfSRobert Mustacchi }
799*dbe930bfSRobert Mustacchi
800*dbe930bfSRobert Mustacchi return (B_TRUE);
801*dbe930bfSRobert Mustacchi }
802*dbe930bfSRobert Mustacchi
803*dbe930bfSRobert Mustacchi /*
804d2d52addSAlexander Pyhalov * Fix patterns.
805d2d52addSAlexander Pyhalov * Must do after all arguments read, in case later -i option.
806d2d52addSAlexander Pyhalov */
807d2d52addSAlexander Pyhalov static void
fixpatterns(void)808d2d52addSAlexander Pyhalov fixpatterns(void)
809d2d52addSAlexander Pyhalov {
810d2d52addSAlexander Pyhalov PATTERN *pp;
81181dd18d8SRobert Mustacchi int rv, fix_pattern;
81281dd18d8SRobert Mustacchi
81381dd18d8SRobert Mustacchi /*
81481dd18d8SRobert Mustacchi * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
81581dd18d8SRobert Mustacchi * Use the Boyer-Moore-Gosper algorithm if:
816*dbe930bfSRobert Mustacchi * - fgrep or non-BRE/ERE (Fflag || simple_pattern())
81781dd18d8SRobert Mustacchi * - singlebyte locale (!mblocale)
81881dd18d8SRobert Mustacchi * - no ignoring case (!iflag)
81981dd18d8SRobert Mustacchi * - no printing line numbers (!nflag)
82081dd18d8SRobert Mustacchi * - no negating the output (nvflag)
82181dd18d8SRobert Mustacchi * - only one pattern (patterns != NULL && patterns->next ==
82281dd18d8SRobert Mustacchi * NULL)
82381dd18d8SRobert Mustacchi * - non zero length pattern (strlen(patterns->pattern) != 0)
82481dd18d8SRobert Mustacchi * - no context required (conflag == 0)
82581dd18d8SRobert Mustacchi * - no exact matches (!oflag)
826*dbe930bfSRobert Mustacchi * - no word matches (!wlag)
82781dd18d8SRobert Mustacchi */
828*dbe930bfSRobert Mustacchi use_bmg = !mblocale && !iflag && !nflag && nvflag && !oflag &&
829*dbe930bfSRobert Mustacchi (patterns != NULL && patterns->next == NULL) && !wflag &&
830*dbe930bfSRobert Mustacchi (strlen(patterns->pattern) != 0) && conflag == 0 &&
831*dbe930bfSRobert Mustacchi (Fflag || simple_pattern(patterns->pattern));
83281dd18d8SRobert Mustacchi
83381dd18d8SRobert Mustacchi if (use_bmg) {
83481dd18d8SRobert Mustacchi return;
83581dd18d8SRobert Mustacchi }
836d2d52addSAlexander Pyhalov
837d2d52addSAlexander Pyhalov /*
838925beec7SYuri Pankov * Fix the specified pattern if -x is specified.
839d2d52addSAlexander Pyhalov */
840d2d52addSAlexander Pyhalov fix_pattern = !Fflag && xflag;
841d2d52addSAlexander Pyhalov
84281dd18d8SRobert Mustacchi for (pp = patterns; pp != NULL; pp = pp->next) {
843d2d52addSAlexander Pyhalov if (fix_pattern) {
844d2d52addSAlexander Pyhalov char *cp, *cq;
845d2d52addSAlexander Pyhalov size_t plen, nplen;
846d2d52addSAlexander Pyhalov
847d2d52addSAlexander Pyhalov plen = strlen(pp->pattern);
848d2d52addSAlexander Pyhalov /* '^' pattern '$' */
849d2d52addSAlexander Pyhalov nplen = 1 + plen + 1 + 1;
850d2d52addSAlexander Pyhalov if ((cp = malloc(nplen)) == NULL) {
851d2d52addSAlexander Pyhalov (void) fprintf(stderr,
852d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
853d2d52addSAlexander Pyhalov cmdname);
854d2d52addSAlexander Pyhalov exit(2);
855d2d52addSAlexander Pyhalov }
856d2d52addSAlexander Pyhalov cq = cp;
857d2d52addSAlexander Pyhalov *cq++ = '^';
858d2d52addSAlexander Pyhalov cq = strcpy(cq, pp->pattern) + plen;
859d2d52addSAlexander Pyhalov *cq++ = '$';
860d2d52addSAlexander Pyhalov *cq = '\0';
861d2d52addSAlexander Pyhalov free(pp->pattern);
862d2d52addSAlexander Pyhalov pp->pattern = cp;
863d2d52addSAlexander Pyhalov }
864d2d52addSAlexander Pyhalov
865d2d52addSAlexander Pyhalov /*
86681dd18d8SRobert Mustacchi * Compile the regular expression, give an informative error
86781dd18d8SRobert Mustacchi * message, and exit if it didn't compile.
868d2d52addSAlexander Pyhalov */
869d2d52addSAlexander Pyhalov if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) {
870d2d52addSAlexander Pyhalov (void) regerror(rv, &pp->re, errstr, sizeof (errstr));
871d2d52addSAlexander Pyhalov (void) fprintf(stderr,
872d2d52addSAlexander Pyhalov gettext("%s: RE error in %s: %s\n"),
873d2d52addSAlexander Pyhalov cmdname, pp->pattern, errstr);
874d2d52addSAlexander Pyhalov exit(2);
875d2d52addSAlexander Pyhalov }
876d2d52addSAlexander Pyhalov free(pp->pattern);
877d2d52addSAlexander Pyhalov }
878d2d52addSAlexander Pyhalov }
879d2d52addSAlexander Pyhalov
880d2d52addSAlexander Pyhalov /*
881d2d52addSAlexander Pyhalov * Search a newline from the beginning of the string
882d2d52addSAlexander Pyhalov */
883d2d52addSAlexander Pyhalov static char *
find_nl(const char * ptr,size_t len)884d2d52addSAlexander Pyhalov find_nl(const char *ptr, size_t len)
885d2d52addSAlexander Pyhalov {
886d2d52addSAlexander Pyhalov while (len-- != 0) {
887d2d52addSAlexander Pyhalov if (*ptr++ == '\n') {
888d2d52addSAlexander Pyhalov return ((char *)--ptr);
889d2d52addSAlexander Pyhalov }
890d2d52addSAlexander Pyhalov }
891d2d52addSAlexander Pyhalov return (NULL);
892d2d52addSAlexander Pyhalov }
893d2d52addSAlexander Pyhalov
894d2d52addSAlexander Pyhalov /*
895d2d52addSAlexander Pyhalov * Search a newline from the end of the string
896d2d52addSAlexander Pyhalov */
897d2d52addSAlexander Pyhalov static char *
rfind_nl(const char * ptr,size_t len)898d2d52addSAlexander Pyhalov rfind_nl(const char *ptr, size_t len)
899d2d52addSAlexander Pyhalov {
900d2d52addSAlexander Pyhalov const char *uptr = ptr + len;
901d2d52addSAlexander Pyhalov while (len--) {
902d2d52addSAlexander Pyhalov if (*--uptr == '\n') {
903d2d52addSAlexander Pyhalov return ((char *)uptr);
904d2d52addSAlexander Pyhalov }
905d2d52addSAlexander Pyhalov }
906d2d52addSAlexander Pyhalov return (NULL);
907d2d52addSAlexander Pyhalov }
908d2d52addSAlexander Pyhalov
909d2d52addSAlexander Pyhalov /*
910d2d52addSAlexander Pyhalov * Do grep on a single file.
911d2d52addSAlexander Pyhalov * Return true in any lines matched.
912d2d52addSAlexander Pyhalov *
913d2d52addSAlexander Pyhalov * We have two strategies:
914d2d52addSAlexander Pyhalov * The fast one is used when we have a single pattern with
915d2d52addSAlexander Pyhalov * a string known to occur in the pattern. We can then
916d2d52addSAlexander Pyhalov * do a BMG match on the whole buffer.
917d2d52addSAlexander Pyhalov * This is an order of magnitude faster.
918d2d52addSAlexander Pyhalov * Otherwise we split the buffer into lines,
919d2d52addSAlexander Pyhalov * and check for a match on each line.
920d2d52addSAlexander Pyhalov */
921d2d52addSAlexander Pyhalov static int
grep(int fd,const char * fn)922d2d52addSAlexander Pyhalov grep(int fd, const char *fn)
923d2d52addSAlexander Pyhalov {
924d2d52addSAlexander Pyhalov PATTERN *pp;
925d2d52addSAlexander Pyhalov off_t data_len; /* length of the data chunk */
926d2d52addSAlexander Pyhalov off_t line_len; /* length of the current line */
927d2d52addSAlexander Pyhalov off_t line_offset; /* current line's offset from the beginning */
928d2d52addSAlexander Pyhalov off_t blkoffset; /* line_offset but context-compatible */
929d2d52addSAlexander Pyhalov long long lineno, linenum;
930d2d52addSAlexander Pyhalov long long matches = 0; /* Number of matching lines */
931d2d52addSAlexander Pyhalov long long conacnt = 0, conbcnt = 0; /* context line count */
932d2d52addSAlexander Pyhalov int newlinep; /* 0 if the last line of file has no newline */
933d2d52addSAlexander Pyhalov char *ptr, *ptrend, *prntptr, *prntptrend;
934d2d52addSAlexander Pyhalov char *nextptr = NULL, *nextend = NULL;
935d2d52addSAlexander Pyhalov char *conptr = NULL, *conptrend = NULL;
936d2d52addSAlexander Pyhalov char *matchptr = NULL;
937d2d52addSAlexander Pyhalov int conaprnt = 0, conbprnt = 0, lastmatch = 0;
938d2d52addSAlexander Pyhalov boolean_t nearmatch; /* w/in N+1 of last match */
939d2d52addSAlexander Pyhalov boolean_t havematch = B_FALSE; /* have a match in context */
94081dd18d8SRobert Mustacchi boolean_t sameline = B_FALSE; /* Are we still on the same line? */
941d2d52addSAlexander Pyhalov size_t prntlen;
942d2d52addSAlexander Pyhalov
943d2d52addSAlexander Pyhalov if (patterns == NULL)
944d2d52addSAlexander Pyhalov return (0); /* no patterns to match -- just return */
945d2d52addSAlexander Pyhalov
946d2d52addSAlexander Pyhalov pp = patterns;
947d2d52addSAlexander Pyhalov
948d2d52addSAlexander Pyhalov if (use_bmg) {
949d2d52addSAlexander Pyhalov bmgcomp(pp->pattern, strlen(pp->pattern));
950d2d52addSAlexander Pyhalov }
951d2d52addSAlexander Pyhalov
9527c478bd9Sstevel@tonic-gate if (prntbuf == NULL) {
953d2d52addSAlexander Pyhalov prntbuflen = BUFSIZE;
954d2d52addSAlexander Pyhalov if ((prntbuf = malloc(prntbuflen + 1)) == NULL) {
955d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"),
956d2d52addSAlexander Pyhalov cmdname);
957d2d52addSAlexander Pyhalov exit(2);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate
961d2d52addSAlexander Pyhalov if (conflag != 0 && (conbuf == NULL)) {
962d2d52addSAlexander Pyhalov conbuflen = BUFSIZE;
963d2d52addSAlexander Pyhalov if ((conbuf = malloc(BUFSIZE+1)) == NULL) {
964d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"),
965d2d52addSAlexander Pyhalov cmdname);
966d2d52addSAlexander Pyhalov exit(2);
967d2d52addSAlexander Pyhalov }
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate
970d2d52addSAlexander Pyhalov nearmatch = (conmatches != 0);
971d2d52addSAlexander Pyhalov blkoffset = line_offset = 0;
972d2d52addSAlexander Pyhalov lineno = 0;
973d2d52addSAlexander Pyhalov linenum = 1;
974d2d52addSAlexander Pyhalov newlinep = 1;
975d2d52addSAlexander Pyhalov data_len = 0;
9767c478bd9Sstevel@tonic-gate for (; ; ) {
977d2d52addSAlexander Pyhalov long count;
978d2d52addSAlexander Pyhalov off_t offset = 0;
979d2d52addSAlexander Pyhalov char separate;
98081dd18d8SRobert Mustacchi char *startmatch = NULL; /* -o, start of match */
98181dd18d8SRobert Mustacchi char *postmatch = NULL; /* -o, character after match */
982d2d52addSAlexander Pyhalov boolean_t last_ctx = B_FALSE, eof = B_FALSE;
9837c478bd9Sstevel@tonic-gate
984d2d52addSAlexander Pyhalov if (data_len == 0) {
9857c478bd9Sstevel@tonic-gate /*
986d2d52addSAlexander Pyhalov * If no data in the buffer, reset ptr
9877c478bd9Sstevel@tonic-gate */
9887c478bd9Sstevel@tonic-gate ptr = prntbuf;
989d2d52addSAlexander Pyhalov if (conflag != 0 && conptr == NULL) {
990d2d52addSAlexander Pyhalov conptr = conbuf;
991d2d52addSAlexander Pyhalov conptrend = conptr - 1;
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate }
994d2d52addSAlexander Pyhalov if (ptr == prntbuf) {
995d2d52addSAlexander Pyhalov /*
996d2d52addSAlexander Pyhalov * The current data chunk starts from prntbuf.
997d2d52addSAlexander Pyhalov * This means either the buffer has no data
998d2d52addSAlexander Pyhalov * or the buffer has no newline.
999d2d52addSAlexander Pyhalov * So, read more data from input.
1000d2d52addSAlexander Pyhalov */
1001d2d52addSAlexander Pyhalov count = read(fd, ptr + data_len, prntbuflen - data_len);
1002d2d52addSAlexander Pyhalov if (count < 0) {
1003d2d52addSAlexander Pyhalov /* read error */
1004d2d52addSAlexander Pyhalov if (cflag) {
1005d2d52addSAlexander Pyhalov if (outfn && !rflag) {
1006d2d52addSAlexander Pyhalov (void) fprintf(stdout,
1007d2d52addSAlexander Pyhalov "%s:", fn);
1008d2d52addSAlexander Pyhalov }
1009d2d52addSAlexander Pyhalov if (!qflag && !rflag) {
1010d2d52addSAlexander Pyhalov (void) fprintf(stdout, "%lld\n",
1011d2d52addSAlexander Pyhalov matches);
1012d2d52addSAlexander Pyhalov }
1013d2d52addSAlexander Pyhalov }
1014d2d52addSAlexander Pyhalov return (0);
1015d2d52addSAlexander Pyhalov } else if (count == 0) {
1016d2d52addSAlexander Pyhalov /* no new data */
1017d2d52addSAlexander Pyhalov eof = B_TRUE;
10187c478bd9Sstevel@tonic-gate
1019d2d52addSAlexander Pyhalov if (data_len == 0) {
10207c478bd9Sstevel@tonic-gate /* end of file already reached */
1021d2d52addSAlexander Pyhalov if (conflag != 0) {
1022d2d52addSAlexander Pyhalov if (conptrend >= conptr)
1023d2d52addSAlexander Pyhalov *conptrend = '\n';
1024d2d52addSAlexander Pyhalov last_ctx = B_TRUE;
1025d2d52addSAlexander Pyhalov goto L_next_line;
10267c478bd9Sstevel@tonic-gate } else {
1027d2d52addSAlexander Pyhalov goto out;
10287c478bd9Sstevel@tonic-gate }
1029d2d52addSAlexander Pyhalov }
1030d2d52addSAlexander Pyhalov /* last line of file has no newline */
1031d2d52addSAlexander Pyhalov ptrend = ptr + data_len;
1032d2d52addSAlexander Pyhalov newlinep = 0;
1033d2d52addSAlexander Pyhalov goto L_start_process;
1034d2d52addSAlexander Pyhalov }
1035d2d52addSAlexander Pyhalov offset = data_len;
1036d2d52addSAlexander Pyhalov data_len += count;
1037d2d52addSAlexander Pyhalov }
1038d2d52addSAlexander Pyhalov
1039d2d52addSAlexander Pyhalov /*
1040d2d52addSAlexander Pyhalov * Look for newline in the chunk
1041d2d52addSAlexander Pyhalov * between ptr + offset and ptr + data_len - offset.
1042d2d52addSAlexander Pyhalov */
1043d2d52addSAlexander Pyhalov ptrend = find_nl(ptr + offset, data_len - offset);
1044d2d52addSAlexander Pyhalov if (ptrend == NULL) {
1045d2d52addSAlexander Pyhalov /* no newline found in this chunk */
1046d2d52addSAlexander Pyhalov if (ptr > prntbuf) {
1047d2d52addSAlexander Pyhalov /*
1048d2d52addSAlexander Pyhalov * Move remaining data to the beginning
1049d2d52addSAlexander Pyhalov * of the buffer.
1050d2d52addSAlexander Pyhalov * Remaining data lie from ptr for
1051d2d52addSAlexander Pyhalov * data_len bytes.
1052d2d52addSAlexander Pyhalov */
1053d2d52addSAlexander Pyhalov (void) memmove(prntbuf, ptr, data_len);
1054d2d52addSAlexander Pyhalov }
1055d2d52addSAlexander Pyhalov if (data_len == prntbuflen) {
1056d2d52addSAlexander Pyhalov /*
1057d2d52addSAlexander Pyhalov * Not enough room in the buffer
1058d2d52addSAlexander Pyhalov */
1059d2d52addSAlexander Pyhalov if (prntbuflen > SIZE_MAX - BUFSIZE) {
1060d2d52addSAlexander Pyhalov (void) fprintf(stderr,
1061d2d52addSAlexander Pyhalov gettext("%s: buflen would"
1062d2d52addSAlexander Pyhalov " overflow\n"),
1063d2d52addSAlexander Pyhalov cmdname);
1064d2d52addSAlexander Pyhalov exit(2);
1065d2d52addSAlexander Pyhalov }
1066d2d52addSAlexander Pyhalov
1067d2d52addSAlexander Pyhalov prntbuflen += BUFSIZE;
1068d2d52addSAlexander Pyhalov prntbuf = realloc(prntbuf, prntbuflen + 1);
1069d2d52addSAlexander Pyhalov if (prntbuf == NULL) {
1070d2d52addSAlexander Pyhalov (void) fprintf(stderr,
1071d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
1072d2d52addSAlexander Pyhalov cmdname);
1073d2d52addSAlexander Pyhalov exit(2);
1074d2d52addSAlexander Pyhalov }
1075d2d52addSAlexander Pyhalov }
1076d2d52addSAlexander Pyhalov ptr = prntbuf;
1077d2d52addSAlexander Pyhalov /* read the next input */
1078d2d52addSAlexander Pyhalov continue;
1079d2d52addSAlexander Pyhalov }
1080d2d52addSAlexander Pyhalov L_start_process:
1081d2d52addSAlexander Pyhalov
1082d2d52addSAlexander Pyhalov /*
1083d2d52addSAlexander Pyhalov * Beginning of the chunk: ptr
1084d2d52addSAlexander Pyhalov * End of the chunk: ptr + data_len
1085d2d52addSAlexander Pyhalov * Beginning of the line: ptr
1086d2d52addSAlexander Pyhalov * End of the line: ptrend
1087d2d52addSAlexander Pyhalov *
1088d2d52addSAlexander Pyhalov * conptr: Beginning of the context.
1089d2d52addSAlexander Pyhalov * conptrend: If context is empty, conptr - 1 (invalid memory).
1090d2d52addSAlexander Pyhalov * Otherwise, Last newline in the context.
1091d2d52addSAlexander Pyhalov */
1092d2d52addSAlexander Pyhalov
1093d2d52addSAlexander Pyhalov if (use_bmg) {
1094d2d52addSAlexander Pyhalov /*
1095d2d52addSAlexander Pyhalov * Use Boyer-Moore-Gosper algorithm to find out if
1096d2d52addSAlexander Pyhalov * this chunk (not this line) contains the specified
1097d2d52addSAlexander Pyhalov * pattern. If not, restart from the last line
1098d2d52addSAlexander Pyhalov * of this chunk.
1099d2d52addSAlexander Pyhalov */
1100d2d52addSAlexander Pyhalov char *bline;
1101d2d52addSAlexander Pyhalov bline = bmgexec(ptr, ptr + data_len);
1102d2d52addSAlexander Pyhalov if (bline == NULL) {
1103d2d52addSAlexander Pyhalov /*
1104d2d52addSAlexander Pyhalov * No pattern found in this chunk.
1105d2d52addSAlexander Pyhalov * Need to find the last line
1106d2d52addSAlexander Pyhalov * in this chunk.
1107d2d52addSAlexander Pyhalov */
1108d2d52addSAlexander Pyhalov ptrend = rfind_nl(ptr, data_len);
1109d2d52addSAlexander Pyhalov
1110d2d52addSAlexander Pyhalov /*
1111d2d52addSAlexander Pyhalov * When this chunk does not contain newline,
1112d2d52addSAlexander Pyhalov * ptrend becomes NULL, which should happen
1113d2d52addSAlexander Pyhalov * when the last line of file does not end
1114d2d52addSAlexander Pyhalov * with a newline. At such a point,
1115d2d52addSAlexander Pyhalov * newlinep should have been set to 0.
1116d2d52addSAlexander Pyhalov * Therefore, just after jumping to
1117d2d52addSAlexander Pyhalov * L_skip_line, the main for-loop quits,
1118d2d52addSAlexander Pyhalov * and the line_len value won't be
1119d2d52addSAlexander Pyhalov * used.
1120d2d52addSAlexander Pyhalov */
1121d2d52addSAlexander Pyhalov line_len = ptrend - ptr;
1122d2d52addSAlexander Pyhalov goto L_skip_line;
1123d2d52addSAlexander Pyhalov }
1124d2d52addSAlexander Pyhalov if (bline > ptrend) {
1125d2d52addSAlexander Pyhalov /*
1126d2d52addSAlexander Pyhalov * Pattern found not in the first line
1127d2d52addSAlexander Pyhalov * of this chunk.
1128d2d52addSAlexander Pyhalov * Discard the first line.
1129d2d52addSAlexander Pyhalov */
1130d2d52addSAlexander Pyhalov line_len = ptrend - ptr;
1131d2d52addSAlexander Pyhalov goto L_skip_line;
1132d2d52addSAlexander Pyhalov }
1133d2d52addSAlexander Pyhalov /*
1134d2d52addSAlexander Pyhalov * Pattern found in the first line of this chunk.
1135d2d52addSAlexander Pyhalov * Using this result.
1136d2d52addSAlexander Pyhalov */
11377c478bd9Sstevel@tonic-gate *ptrend = '\0';
1138d2d52addSAlexander Pyhalov line_len = ptrend - ptr;
1139d2d52addSAlexander Pyhalov
1140d2d52addSAlexander Pyhalov /*
1141d2d52addSAlexander Pyhalov * before jumping to L_next_line,
1142d2d52addSAlexander Pyhalov * need to handle xflag if specified
1143d2d52addSAlexander Pyhalov */
1144d2d52addSAlexander Pyhalov if (xflag && (line_len != bmglen ||
1145d2d52addSAlexander Pyhalov strcmp(bmgpat, ptr) != 0)) {
1146d2d52addSAlexander Pyhalov /* didn't match */
1147d2d52addSAlexander Pyhalov pp = NULL;
1148d2d52addSAlexander Pyhalov } else {
1149d2d52addSAlexander Pyhalov pp = patterns; /* to make it happen */
1150d2d52addSAlexander Pyhalov }
1151d2d52addSAlexander Pyhalov goto L_next_line;
1152d2d52addSAlexander Pyhalov }
115381dd18d8SRobert Mustacchi
115481dd18d8SRobert Mustacchi /*
115581dd18d8SRobert Mustacchi * When using -o, we might actually loop around while still on
115681dd18d8SRobert Mustacchi * the same line. In such a case, we need to make sure we don't
115781dd18d8SRobert Mustacchi * increment the line number.
115881dd18d8SRobert Mustacchi */
115981dd18d8SRobert Mustacchi if (!sameline) {
1160d2d52addSAlexander Pyhalov lineno++;
116181dd18d8SRobert Mustacchi } else {
116281dd18d8SRobert Mustacchi sameline = B_FALSE;
116381dd18d8SRobert Mustacchi }
116481dd18d8SRobert Mustacchi
1165d2d52addSAlexander Pyhalov /*
1166d2d52addSAlexander Pyhalov * Line starts from ptr and ends at ptrend.
1167d2d52addSAlexander Pyhalov * line_len will be the length of the line.
1168d2d52addSAlexander Pyhalov */
1169d2d52addSAlexander Pyhalov *ptrend = '\0';
1170d2d52addSAlexander Pyhalov line_len = ptrend - ptr;
1171d2d52addSAlexander Pyhalov
1172d2d52addSAlexander Pyhalov /*
1173d2d52addSAlexander Pyhalov * From now, the process will be performed based
1174d2d52addSAlexander Pyhalov * on the line from ptr to ptrend.
1175d2d52addSAlexander Pyhalov */
1176d2d52addSAlexander Pyhalov for (pp = patterns; pp; pp = pp->next) {
1177d2d52addSAlexander Pyhalov int rv;
117881dd18d8SRobert Mustacchi regmatch_t rm;
117981dd18d8SRobert Mustacchi size_t nmatch = 0;
1180d2d52addSAlexander Pyhalov
118181dd18d8SRobert Mustacchi /*
118281dd18d8SRobert Mustacchi * The current implementation of regexec has a higher
118381dd18d8SRobert Mustacchi * cost when you ask for match information. As a result,
118481dd18d8SRobert Mustacchi * we only ask for a match when we know that we need it
118581dd18d8SRobert Mustacchi * specifically. This is always needed for -o because we
118681dd18d8SRobert Mustacchi * rely on it to tell us what we matched. For fgrep -x
118781dd18d8SRobert Mustacchi * we need it so we can determine whether we matched the
118881dd18d8SRobert Mustacchi * entire line.
118981dd18d8SRobert Mustacchi */
119081dd18d8SRobert Mustacchi if (oflag || (Fflag && xflag))
119181dd18d8SRobert Mustacchi nmatch = 1;
119281dd18d8SRobert Mustacchi
119381dd18d8SRobert Mustacchi rv = regexec(&pp->re, ptr, nmatch, &rm, 0);
1194d2d52addSAlexander Pyhalov if (rv == REG_OK) {
119581dd18d8SRobert Mustacchi /*
119681dd18d8SRobert Mustacchi * fgrep in this form cannot insert the
119781dd18d8SRobert Mustacchi * metacharacters to verify whether or not we
119881dd18d8SRobert Mustacchi * were the entire line. As a result, we check
119981dd18d8SRobert Mustacchi * the pattern length against the line length.
120081dd18d8SRobert Mustacchi */
120181dd18d8SRobert Mustacchi if (Fflag && xflag &&
120281dd18d8SRobert Mustacchi line_len != rm.rm_eo - rm.rm_so) {
120381dd18d8SRobert Mustacchi continue;
120481dd18d8SRobert Mustacchi }
120581dd18d8SRobert Mustacchi
1206d2d52addSAlexander Pyhalov /* matched */
120781dd18d8SRobert Mustacchi if (oflag) {
120881dd18d8SRobert Mustacchi startmatch = ptr + rm.rm_so;
120981dd18d8SRobert Mustacchi postmatch = ptr + rm.rm_eo;
121081dd18d8SRobert Mustacchi }
1211d2d52addSAlexander Pyhalov break;
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate
1214d2d52addSAlexander Pyhalov switch (rv) {
1215d2d52addSAlexander Pyhalov case REG_NOMATCH:
12167c478bd9Sstevel@tonic-gate break;
1217d2d52addSAlexander Pyhalov case REG_ECHAR:
1218d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
1219d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1220d2d52addSAlexander Pyhalov cmdname, fn, lineno);
12217c478bd9Sstevel@tonic-gate break;
12227c478bd9Sstevel@tonic-gate default:
1223d2d52addSAlexander Pyhalov (void) regerror(rv, &pp->re, errstr,
1224d2d52addSAlexander Pyhalov sizeof (errstr));
1225d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext(
1226d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: %s\n"),
1227d2d52addSAlexander Pyhalov cmdname, fn, lineno, errstr);
1228d2d52addSAlexander Pyhalov exit(2);
1229d2d52addSAlexander Pyhalov }
1230d2d52addSAlexander Pyhalov }
12317c478bd9Sstevel@tonic-gate
1232d2d52addSAlexander Pyhalov /*
1233d2d52addSAlexander Pyhalov * Context is set up as follows:
1234d2d52addSAlexander Pyhalov * For a 'Before' context, we maintain a set of pointers
1235d2d52addSAlexander Pyhalov * containing 'N' lines of context. If the current number of
1236d2d52addSAlexander Pyhalov * lines contained is greater than N, and N isn't a match, the
1237d2d52addSAlexander Pyhalov * start pointer is moved forward to the next newline.
1238d2d52addSAlexander Pyhalov *
1239d2d52addSAlexander Pyhalov * If we ever find a match, we print out immediately.
1240d2d52addSAlexander Pyhalov * 'nearmatch' tells us if we're within N+1 lines of the last
1241d2d52addSAlexander Pyhalov * match ; if we are, and we find another match, we don't
1242d2d52addSAlexander Pyhalov * separate the matches. 'nearmatch' becomes false when
1243d2d52addSAlexander Pyhalov * a line gets rotated out of the context.
1244d2d52addSAlexander Pyhalov *
1245d2d52addSAlexander Pyhalov * For an 'After' context, we simply wait until we've found a
1246d2d52addSAlexander Pyhalov * match, then create a context N+1 lines big. If we don't find
1247d2d52addSAlexander Pyhalov * a match within the context, we print out the current context.
1248d2d52addSAlexander Pyhalov * Otherwise, we save a reference to the new matching line,
1249d2d52addSAlexander Pyhalov * print out the other context, and reset our context pointers
1250d2d52addSAlexander Pyhalov * to the new matching line.
1251d2d52addSAlexander Pyhalov *
1252d2d52addSAlexander Pyhalov * 'nearmatch' becomes false when we find a non-matching line
1253d2d52addSAlexander Pyhalov * that isn't a part of any context.
1254d2d52addSAlexander Pyhalov *
1255d2d52addSAlexander Pyhalov * A full-context is implemented as a combination of the
1256d2d52addSAlexander Pyhalov * 'Before' and 'After' context logic. Before we find a match,
1257d2d52addSAlexander Pyhalov * we follow the Before logic. When we find a match, we
1258d2d52addSAlexander Pyhalov * follow the After logic. 'nearmatch' is handled by the Before
1259d2d52addSAlexander Pyhalov * logic.
1260d2d52addSAlexander Pyhalov */
1261d2d52addSAlexander Pyhalov
1262d2d52addSAlexander Pyhalov if (conflag == 0)
1263d2d52addSAlexander Pyhalov goto L_next_line;
1264d2d52addSAlexander Pyhalov
1265d2d52addSAlexander Pyhalov /* Do we have room to add this line to the context buffer? */
1266d9241f99SAndrew Stormont while ((line_len + 1) > (conbuflen -
1267d9241f99SAndrew Stormont ((conptrend >= conptr) ? conptrend - conbuf : 0))) {
1268d2d52addSAlexander Pyhalov char *oldconbuf = conbuf;
1269d2d52addSAlexander Pyhalov char *oldconptr = conptr;
1270d2d52addSAlexander Pyhalov long tmp = matchptr - conptr;
1271d2d52addSAlexander Pyhalov
1272d2d52addSAlexander Pyhalov if (conbuflen > SIZE_MAX - BUFSIZE) {
1273d2d52addSAlexander Pyhalov (void) fprintf(stderr,
1274d2d52addSAlexander Pyhalov gettext("%s: buflen would overflow\n"),
1275d2d52addSAlexander Pyhalov cmdname);
12767c478bd9Sstevel@tonic-gate exit(2);
12777c478bd9Sstevel@tonic-gate }
1278d2d52addSAlexander Pyhalov
1279d2d52addSAlexander Pyhalov conbuflen += BUFSIZE;
1280d2d52addSAlexander Pyhalov conbuf = realloc(conbuf, conbuflen + 1);
1281d2d52addSAlexander Pyhalov if (conbuf == NULL) {
1282d2d52addSAlexander Pyhalov (void) fprintf(stderr,
1283d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"),
1284d2d52addSAlexander Pyhalov cmdname);
1285d2d52addSAlexander Pyhalov exit(2);
1286d2d52addSAlexander Pyhalov }
1287d2d52addSAlexander Pyhalov
1288d2d52addSAlexander Pyhalov conptr = conbuf + (conptr - oldconbuf);
1289d2d52addSAlexander Pyhalov conptrend = conptr + (conptrend - oldconptr);
1290d2d52addSAlexander Pyhalov if (matchptr)
1291d2d52addSAlexander Pyhalov matchptr = conptr + tmp;
1292d2d52addSAlexander Pyhalov }
1293d2d52addSAlexander Pyhalov (void) memcpy(conptrend + 1, ptr, line_len);
1294d2d52addSAlexander Pyhalov conptrend += line_len + 1;
1295d2d52addSAlexander Pyhalov *conptrend = '\n';
1296d2d52addSAlexander Pyhalov
1297d2d52addSAlexander Pyhalov if (nvflag == (pp != NULL)) {
1298d2d52addSAlexander Pyhalov /* matched */
1299d2d52addSAlexander Pyhalov if (havematch) {
1300d2d52addSAlexander Pyhalov if ((conflag & AFTER) != 0) {
1301d2d52addSAlexander Pyhalov conaprnt = 1;
1302d2d52addSAlexander Pyhalov nextend = conptrend;
1303d2d52addSAlexander Pyhalov conptrend = conptr + lastmatch;
1304d2d52addSAlexander Pyhalov nextptr = conptrend + 1;
1305d2d52addSAlexander Pyhalov *nextend = '\n';
1306d2d52addSAlexander Pyhalov }
1307d2d52addSAlexander Pyhalov } else {
1308d2d52addSAlexander Pyhalov if (conflag == AFTER) {
1309d2d52addSAlexander Pyhalov conptr = conptrend - (line_len);
1310d2d52addSAlexander Pyhalov linenum = lineno;
1311d2d52addSAlexander Pyhalov }
1312d2d52addSAlexander Pyhalov blkoffset = line_offset -
1313d2d52addSAlexander Pyhalov (conptrend - conptr - line_len);
1314d2d52addSAlexander Pyhalov }
1315d2d52addSAlexander Pyhalov
1316d2d52addSAlexander Pyhalov if (conflag == BEFORE)
1317d2d52addSAlexander Pyhalov conbprnt = 1;
1318d2d52addSAlexander Pyhalov
1319d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr;
1320d2d52addSAlexander Pyhalov havematch = B_TRUE;
1321d2d52addSAlexander Pyhalov goto L_next_line;
1322d2d52addSAlexander Pyhalov }
1323d2d52addSAlexander Pyhalov
1324d2d52addSAlexander Pyhalov if (!havematch) {
1325d2d52addSAlexander Pyhalov if ((conflag & BEFORE) != 0) {
1326d2d52addSAlexander Pyhalov if (conbcnt >= conblen) {
1327d2d52addSAlexander Pyhalov char *tmp = conptr;
1328d2d52addSAlexander Pyhalov conptr = find_nl(conptr,
1329d2d52addSAlexander Pyhalov conptrend - conptr) + 1;
1330d2d52addSAlexander Pyhalov if (bflag)
1331d2d52addSAlexander Pyhalov blkoffset += conptr - tmp;
1332d2d52addSAlexander Pyhalov linenum++;
1333d2d52addSAlexander Pyhalov nearmatch = B_TRUE;
1334d2d52addSAlexander Pyhalov } else {
1335d2d52addSAlexander Pyhalov conbcnt++;
1336d2d52addSAlexander Pyhalov }
1337d2d52addSAlexander Pyhalov }
1338d2d52addSAlexander Pyhalov if (conflag == AFTER)
1339d2d52addSAlexander Pyhalov nearmatch = B_TRUE;
1340d2d52addSAlexander Pyhalov } else {
1341d2d52addSAlexander Pyhalov if (++conacnt >= conalen && !conaprnt && conalen)
1342d2d52addSAlexander Pyhalov conaprnt = 1;
1343d2d52addSAlexander Pyhalov else
1344d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr;
1345d2d52addSAlexander Pyhalov }
1346d2d52addSAlexander Pyhalov
1347d2d52addSAlexander Pyhalov L_next_line:
1348d2d52addSAlexander Pyhalov /*
1349d2d52addSAlexander Pyhalov * Here, if pp points to non-NULL, something has been matched
1350d2d52addSAlexander Pyhalov * to the pattern.
1351d2d52addSAlexander Pyhalov */
1352d2d52addSAlexander Pyhalov if (!last_ctx && nvflag == (pp != NULL)) {
1353d2d52addSAlexander Pyhalov matches++;
135481dd18d8SRobert Mustacchi if (!nextend) {
135581dd18d8SRobert Mustacchi if (conflag != 0) {
135681dd18d8SRobert Mustacchi matchptr = conptrend;
135781dd18d8SRobert Mustacchi } else if (oflag) {
135881dd18d8SRobert Mustacchi matchptr = postmatch - 1;
135981dd18d8SRobert Mustacchi } else {
136081dd18d8SRobert Mustacchi matchptr = ptrend;
136181dd18d8SRobert Mustacchi }
136281dd18d8SRobert Mustacchi }
136381dd18d8SRobert Mustacchi }
136481dd18d8SRobert Mustacchi
136581dd18d8SRobert Mustacchi if (pp != NULL && oflag && postmatch == NULL) {
136681dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext("%s: internal error, "
136781dd18d8SRobert Mustacchi "-o set, but failed to find postmatch\n"), cmdname);
136881dd18d8SRobert Mustacchi abort();
1369d2d52addSAlexander Pyhalov }
1370d2d52addSAlexander Pyhalov
1371d2d52addSAlexander Pyhalov /*
1372d2d52addSAlexander Pyhalov * Set up some print context so that we can treat
1373d2d52addSAlexander Pyhalov * single-line matches as a zero-N context.
1374d2d52addSAlexander Pyhalov * Apply CLI flags to each line of the context.
1375d2d52addSAlexander Pyhalov *
1376d2d52addSAlexander Pyhalov * For context, we only print if we both have a match and are
1377d2d52addSAlexander Pyhalov * either at the end of the data stream, or we've previously
1378d2d52addSAlexander Pyhalov * declared that we want to print for a particular context.
1379d2d52addSAlexander Pyhalov */
1380d2d52addSAlexander Pyhalov if (havematch && (eof || conaprnt || conbprnt)) {
1381d2d52addSAlexander Pyhalov
1382d2d52addSAlexander Pyhalov /*
1383d2d52addSAlexander Pyhalov * We'd normally do this earlier, but we had to
1384d2d52addSAlexander Pyhalov * escape early because we reached the end of the data.
1385d2d52addSAlexander Pyhalov */
1386d2d52addSAlexander Pyhalov if (eof && nextptr)
1387d2d52addSAlexander Pyhalov conptrend = nextend;
1388d2d52addSAlexander Pyhalov
1389d2d52addSAlexander Pyhalov prntlen = conptrend - conptr + 1;
1390d2d52addSAlexander Pyhalov prntptr = conptr;
1391d2d52addSAlexander Pyhalov if (conmatches++ && nearmatch && !cflag)
1392d2d52addSAlexander Pyhalov (void) fwrite("--\n", 1, 3, stdout);
1393d2d52addSAlexander Pyhalov } else if (conflag == 0 && nvflag == (pp != NULL)) {
1394d2d52addSAlexander Pyhalov *ptrend = '\n';
139581dd18d8SRobert Mustacchi if (oflag) {
139681dd18d8SRobert Mustacchi prntptr = startmatch;
139781dd18d8SRobert Mustacchi } else {
1398d2d52addSAlexander Pyhalov prntptr = ptr;
139981dd18d8SRobert Mustacchi }
140081dd18d8SRobert Mustacchi prntlen = line_len + 1;
1401d2d52addSAlexander Pyhalov linenum = lineno;
1402d2d52addSAlexander Pyhalov blkoffset = line_offset;
140381dd18d8SRobert Mustacchi if (oflag) {
140481dd18d8SRobert Mustacchi blkoffset += startmatch - ptr;
140581dd18d8SRobert Mustacchi }
1406d2d52addSAlexander Pyhalov } else if (eof) {
1407d2d52addSAlexander Pyhalov /* No match and no more data */
1408d2d52addSAlexander Pyhalov goto out;
1409d2d52addSAlexander Pyhalov } else {
1410d2d52addSAlexander Pyhalov /* No match, or we're not done building context */
1411d2d52addSAlexander Pyhalov goto L_skip_line;
1412d2d52addSAlexander Pyhalov }
1413d2d52addSAlexander Pyhalov
141481dd18d8SRobert Mustacchi if (oflag) {
141581dd18d8SRobert Mustacchi prntptrend = postmatch - 1;
141681dd18d8SRobert Mustacchi } else {
1417d2d52addSAlexander Pyhalov prntptrend = prntptr - 1;
141881dd18d8SRobert Mustacchi }
141981dd18d8SRobert Mustacchi while (oflag || (prntptrend = find_nl(prntptrend + 1,
1420d2d52addSAlexander Pyhalov prntlen)) != NULL) {
1421d2d52addSAlexander Pyhalov /*
1422d2d52addSAlexander Pyhalov * GNU grep uses '-' for context lines and ':' for
1423d2d52addSAlexander Pyhalov * matching lines, so replicate that here.
1424d2d52addSAlexander Pyhalov */
1425d2d52addSAlexander Pyhalov if (prntptrend == matchptr) {
1426d2d52addSAlexander Pyhalov if (eof && nextptr) {
1427d2d52addSAlexander Pyhalov matchptr = nextend;
1428d2d52addSAlexander Pyhalov nextptr = NULL;
1429d2d52addSAlexander Pyhalov } else {
1430d2d52addSAlexander Pyhalov matchptr = NULL;
1431d2d52addSAlexander Pyhalov }
1432d2d52addSAlexander Pyhalov separate = ':';
1433d2d52addSAlexander Pyhalov } else {
1434d2d52addSAlexander Pyhalov separate = '-';
1435d2d52addSAlexander Pyhalov }
1436d2d52addSAlexander Pyhalov
1437d2d52addSAlexander Pyhalov /*
1438d2d52addSAlexander Pyhalov * Handle q, l, and c flags.
1439d2d52addSAlexander Pyhalov */
1440d2d52addSAlexander Pyhalov if (qflag) {
1441d2d52addSAlexander Pyhalov /* no need to continue */
1442d2d52addSAlexander Pyhalov /*
1443d2d52addSAlexander Pyhalov * End of this line is ptrend.
1444d2d52addSAlexander Pyhalov * We have read up to ptr + data_len.
1445d2d52addSAlexander Pyhalov */
1446d2d52addSAlexander Pyhalov off_t pos;
1447d2d52addSAlexander Pyhalov pos = ptr + data_len - (ptrend + 1);
1448d2d52addSAlexander Pyhalov (void) lseek(fd, -pos, SEEK_CUR);
1449d2d52addSAlexander Pyhalov exit(0);
1450d2d52addSAlexander Pyhalov }
1451d2d52addSAlexander Pyhalov if (lflag) {
1452d2d52addSAlexander Pyhalov (void) printf("%s\n", fn);
1453d2d52addSAlexander Pyhalov goto out;
1454d2d52addSAlexander Pyhalov }
14552e5ac464SRobert Mustacchi if (Lflag) {
14562e5ac464SRobert Mustacchi goto out;
14572e5ac464SRobert Mustacchi }
1458d2d52addSAlexander Pyhalov if (!cflag) {
1459d2d52addSAlexander Pyhalov if (Hflag || outfn) {
1460d2d52addSAlexander Pyhalov (void) printf("%s%c", fn, separate);
1461d2d52addSAlexander Pyhalov }
1462d2d52addSAlexander Pyhalov if (bflag) {
1463d2d52addSAlexander Pyhalov (void) printf("%lld%c", (offset_t)
1464d2d52addSAlexander Pyhalov (blkoffset / BSIZE), separate);
1465d2d52addSAlexander Pyhalov }
1466d2d52addSAlexander Pyhalov if (nflag) {
1467d2d52addSAlexander Pyhalov (void) printf("%lld%c", linenum,
1468d2d52addSAlexander Pyhalov separate);
1469d2d52addSAlexander Pyhalov }
1470d2d52addSAlexander Pyhalov (void) fwrite(prntptr, 1,
1471d2d52addSAlexander Pyhalov prntptrend - prntptr + 1, stdout);
147281dd18d8SRobert Mustacchi
147381dd18d8SRobert Mustacchi if (oflag) {
147481dd18d8SRobert Mustacchi (void) fputc('\n', stdout);
147581dd18d8SRobert Mustacchi }
1476d2d52addSAlexander Pyhalov }
1477d2d52addSAlexander Pyhalov if (ferror(stdout)) {
1478d2d52addSAlexander Pyhalov return (0);
1479d2d52addSAlexander Pyhalov }
148081dd18d8SRobert Mustacchi
148181dd18d8SRobert Mustacchi /*
148281dd18d8SRobert Mustacchi * With -o we'll only ever take this loop once. Manually
148381dd18d8SRobert Mustacchi * break out.
148481dd18d8SRobert Mustacchi */
148581dd18d8SRobert Mustacchi if (oflag) {
148681dd18d8SRobert Mustacchi goto L_skip_line;
148781dd18d8SRobert Mustacchi }
148881dd18d8SRobert Mustacchi
1489d2d52addSAlexander Pyhalov linenum++;
1490d2d52addSAlexander Pyhalov prntlen -= prntptrend - prntptr + 1;
1491d2d52addSAlexander Pyhalov blkoffset += prntptrend - prntptr + 1;
1492d2d52addSAlexander Pyhalov prntptr = prntptrend + 1;
1493d2d52addSAlexander Pyhalov }
1494d2d52addSAlexander Pyhalov
1495d2d52addSAlexander Pyhalov if (eof)
1496d2d52addSAlexander Pyhalov goto out;
1497d2d52addSAlexander Pyhalov
1498d2d52addSAlexander Pyhalov /*
1499d2d52addSAlexander Pyhalov * Update context buffer and variables post-print
1500d2d52addSAlexander Pyhalov */
1501d2d52addSAlexander Pyhalov if (conflag != 0) {
1502d2d52addSAlexander Pyhalov conptr = conbuf;
1503d2d52addSAlexander Pyhalov conaprnt = conbprnt = 0;
1504d2d52addSAlexander Pyhalov nearmatch = B_FALSE;
1505d2d52addSAlexander Pyhalov conacnt = conbcnt = 0;
1506d2d52addSAlexander Pyhalov
1507d2d52addSAlexander Pyhalov if (nextptr) {
1508d2d52addSAlexander Pyhalov (void) memmove(conbuf, nextptr,
1509d2d52addSAlexander Pyhalov nextend - nextptr + 1);
1510d2d52addSAlexander Pyhalov blkoffset += nextptr - conptrend - 1;
1511d2d52addSAlexander Pyhalov conptrend = conptr + (nextend - nextptr);
1512d2d52addSAlexander Pyhalov matchptr = conptrend;
1513d2d52addSAlexander Pyhalov linenum = lineno;
1514d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr;
1515d2d52addSAlexander Pyhalov havematch = B_TRUE;
1516d2d52addSAlexander Pyhalov } else {
1517d2d52addSAlexander Pyhalov conptrend = conptr - 1;
1518d2d52addSAlexander Pyhalov conacnt = 0;
1519d2d52addSAlexander Pyhalov lastmatch = 0;
1520d2d52addSAlexander Pyhalov havematch = B_FALSE;
1521d2d52addSAlexander Pyhalov }
1522d2d52addSAlexander Pyhalov nextptr = nextend = NULL;
1523d2d52addSAlexander Pyhalov }
1524d2d52addSAlexander Pyhalov
1525d2d52addSAlexander Pyhalov L_skip_line:
1526d2d52addSAlexander Pyhalov if (!newlinep)
1527d2d52addSAlexander Pyhalov break;
1528d2d52addSAlexander Pyhalov
152981dd18d8SRobert Mustacchi if (oflag && postmatch != NULL) {
153081dd18d8SRobert Mustacchi line_len = postmatch - 1 - ptr;
153181dd18d8SRobert Mustacchi ptr = postmatch;
153281dd18d8SRobert Mustacchi sameline = B_TRUE;
153381dd18d8SRobert Mustacchi } else {
153481dd18d8SRobert Mustacchi ptr = ptrend + 1;
153581dd18d8SRobert Mustacchi }
1536d2d52addSAlexander Pyhalov data_len -= line_len + 1;
1537d2d52addSAlexander Pyhalov line_offset += line_len + 1;
1538d2d52addSAlexander Pyhalov }
1539d2d52addSAlexander Pyhalov
1540d2d52addSAlexander Pyhalov out:
1541d2d52addSAlexander Pyhalov if (cflag) {
1542d2d52addSAlexander Pyhalov if (Hflag || outfn) {
1543d2d52addSAlexander Pyhalov (void) printf("%s:", fn);
1544d2d52addSAlexander Pyhalov }
1545d2d52addSAlexander Pyhalov if (!qflag) {
1546d2d52addSAlexander Pyhalov (void) printf("%lld\n", matches);
1547d2d52addSAlexander Pyhalov }
1548d2d52addSAlexander Pyhalov }
15492e5ac464SRobert Mustacchi
15502e5ac464SRobert Mustacchi /*
15512e5ac464SRobert Mustacchi * -L tells us to print the filename only when it doesn't match. So we
15522e5ac464SRobert Mustacchi * run through the normal operationa and then invert it.
15532e5ac464SRobert Mustacchi */
15542e5ac464SRobert Mustacchi if (Lflag) {
15552e5ac464SRobert Mustacchi if (matches == 0) {
15562e5ac464SRobert Mustacchi (void) printf("%s\n", fn);
15572e5ac464SRobert Mustacchi matches = 1;
15582e5ac464SRobert Mustacchi } else {
15592e5ac464SRobert Mustacchi matches = 0;
15602e5ac464SRobert Mustacchi }
15612e5ac464SRobert Mustacchi }
15622e5ac464SRobert Mustacchi
1563d2d52addSAlexander Pyhalov return (matches != 0);
1564d2d52addSAlexander Pyhalov }
1565d2d52addSAlexander Pyhalov
1566d2d52addSAlexander Pyhalov /*
1567d2d52addSAlexander Pyhalov * usage message for grep
1568d2d52addSAlexander Pyhalov */
1569d2d52addSAlexander Pyhalov static void
usage(void)1570d2d52addSAlexander Pyhalov usage(void)
1571d2d52addSAlexander Pyhalov {
1572e54e6a39SYuri Pankov (void) fprintf(stderr, gettext("usage: %5s"), cmdname);
1573e54e6a39SYuri Pankov if (!egrep && !fgrep)
1574e54e6a39SYuri Pankov (void) fprintf(stderr, gettext(" [-E|-F]"));
157581dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext(" [-bchHilLnoqrRsvx] [-A num] [-B num] "
15768ccd0217SRobert Mustacchi "[-C num|-num]\n [--label=name] [-e pattern_list]... "
15778ccd0217SRobert Mustacchi "[-f pattern_file]...\n [pattern_list] [file]...\n"));
1578d2d52addSAlexander Pyhalov exit(2);
1579d2d52addSAlexander Pyhalov /* NOTREACHED */
1580d2d52addSAlexander Pyhalov }
1581d2d52addSAlexander Pyhalov
1582d2d52addSAlexander Pyhalov /*
1583d2d52addSAlexander Pyhalov * Compile literal pattern into BMG tables
1584d2d52addSAlexander Pyhalov */
1585d2d52addSAlexander Pyhalov static void
bmgcomp(char * pat,int len)1586d2d52addSAlexander Pyhalov bmgcomp(char *pat, int len)
1587d2d52addSAlexander Pyhalov {
1588d2d52addSAlexander Pyhalov int i;
1589d2d52addSAlexander Pyhalov int tlen;
1590d2d52addSAlexander Pyhalov unsigned char *uc = (unsigned char *)pat;
1591d2d52addSAlexander Pyhalov
1592d2d52addSAlexander Pyhalov bmglen = len;
1593d2d52addSAlexander Pyhalov bmgpat = pat;
1594d2d52addSAlexander Pyhalov
1595d2d52addSAlexander Pyhalov for (i = 0; i < M_CSETSIZE; i++) {
1596d2d52addSAlexander Pyhalov bmgtab[i] = len;
1597d2d52addSAlexander Pyhalov }
1598d2d52addSAlexander Pyhalov
1599d2d52addSAlexander Pyhalov len--;
1600d2d52addSAlexander Pyhalov for (tlen = len, i = 0; i <= len; i++, tlen--) {
1601d2d52addSAlexander Pyhalov bmgtab[*uc++] = tlen;
1602d2d52addSAlexander Pyhalov }
1603d2d52addSAlexander Pyhalov }
1604d2d52addSAlexander Pyhalov
1605d2d52addSAlexander Pyhalov /*
1606d2d52addSAlexander Pyhalov * BMG search.
1607d2d52addSAlexander Pyhalov */
1608d2d52addSAlexander Pyhalov static char *
bmgexec(char * str,char * end)1609d2d52addSAlexander Pyhalov bmgexec(char *str, char *end)
1610d2d52addSAlexander Pyhalov {
1611d2d52addSAlexander Pyhalov int t;
1612d2d52addSAlexander Pyhalov char *k, *s, *p;
1613d2d52addSAlexander Pyhalov
1614d2d52addSAlexander Pyhalov k = str + bmglen - 1;
1615d2d52addSAlexander Pyhalov if (bmglen == 1) {
1616d2d52addSAlexander Pyhalov return (memchr(str, bmgpat[0], end - str));
1617d2d52addSAlexander Pyhalov }
1618d2d52addSAlexander Pyhalov for (; ; ) {
1619d2d52addSAlexander Pyhalov /* inner loop, should be most optimized */
1620d2d52addSAlexander Pyhalov while (k < end && (t = bmgtab[(unsigned char)*k]) != 0) {
1621d2d52addSAlexander Pyhalov k += t;
1622d2d52addSAlexander Pyhalov }
1623d2d52addSAlexander Pyhalov if (k >= end) {
1624d2d52addSAlexander Pyhalov return (NULL);
1625d2d52addSAlexander Pyhalov }
1626d2d52addSAlexander Pyhalov for (s = k, p = bmgpat + bmglen - 1; *--s == *--p; ) {
1627d2d52addSAlexander Pyhalov if (p == bmgpat) {
1628d2d52addSAlexander Pyhalov return (s);
1629d2d52addSAlexander Pyhalov }
1630d2d52addSAlexander Pyhalov }
1631d2d52addSAlexander Pyhalov k++;
1632d2d52addSAlexander Pyhalov }
1633d2d52addSAlexander Pyhalov /* NOTREACHED */
1634d2d52addSAlexander Pyhalov }
1635