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 2741599e9fSDamian Bogel /* 28d2d52addSAlexander Pyhalov * grep - pattern matching program - combined grep, egrep, and fgrep. 29d2d52addSAlexander Pyhalov * Based on MKS grep command, with XCU & Solaris mods. 3041599e9fSDamian Bogel */ 3141599e9fSDamian Bogel 327c478bd9Sstevel@tonic-gate /* 33d2d52addSAlexander Pyhalov * Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate 37d2d52addSAlexander Pyhalov /* 384adc6f15SPeter Tribble * Copyright 2020 Peter Tribble. 39d9241f99SAndrew Stormont * Copyright 2018 RackTop Systems. 40925beec7SYuri Pankov * Copyright 2018 Nexenta Systems, Inc. 41d2d52addSAlexander Pyhalov * Copyright 2013 Damian Bogel. All rights reserved. 422e5ac464SRobert Mustacchi * Copyright 2020 Oxide Computer Company 43d2d52addSAlexander Pyhalov */ 44d2d52addSAlexander Pyhalov 45d2d52addSAlexander Pyhalov #include <string.h> 46d2d52addSAlexander Pyhalov #include <stdlib.h> 477c478bd9Sstevel@tonic-gate #include <ctype.h> 48d2d52addSAlexander Pyhalov #include <stdarg.h> 49d2d52addSAlexander Pyhalov #include <regex.h> 50d2d52addSAlexander Pyhalov #include <limits.h> 51d2d52addSAlexander Pyhalov #include <sys/types.h> 52d2d52addSAlexander Pyhalov #include <sys/stat.h> 537c478bd9Sstevel@tonic-gate #include <fcntl.h> 547c478bd9Sstevel@tonic-gate #include <stdio.h> 55d2d52addSAlexander Pyhalov #include <locale.h> 56d2d52addSAlexander Pyhalov #include <wchar.h> 57d2d52addSAlexander Pyhalov #include <errno.h> 587c478bd9Sstevel@tonic-gate #include <unistd.h> 59d2d52addSAlexander Pyhalov #include <wctype.h> 60e52fb54bSAlexander Eremin #include <ftw.h> 61e52fb54bSAlexander Eremin #include <sys/param.h> 628ccd0217SRobert Mustacchi #include <getopt.h> 637c478bd9Sstevel@tonic-gate 64d2d52addSAlexander Pyhalov #define STDIN_FILENAME gettext("(standard input)") 65d2d52addSAlexander Pyhalov 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 */ 69d2d52addSAlexander Pyhalov 704adc6f15SPeter Tribble #define AFTER 1 /* 'After' Context */ 714adc6f15SPeter Tribble #define BEFORE 2 /* 'Before' Context */ 72d2d52addSAlexander Pyhalov #define CONTEXT (AFTER|BEFORE) /* Full Context */ 73d2d52addSAlexander Pyhalov 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; 1184adc6f15SPeter Tribble 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 1328ccd0217SRobert Mustacchi /* 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 146d2d52addSAlexander Pyhalov /* 147d2d52addSAlexander Pyhalov * mainline for grep 148d2d52addSAlexander Pyhalov */ 1497c478bd9Sstevel@tonic-gate int 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 */ 161d2d52addSAlexander Pyhalov #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) 19341599e9fSDamian Bogel 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; 225d2d52addSAlexander Pyhalov switch (c) { 226d2d52addSAlexander Pyhalov case 'v': /* POSIX: negate matches */ 227d2d52addSAlexander Pyhalov nvflag = B_FALSE; 2287c478bd9Sstevel@tonic-gate break; 229d2d52addSAlexander Pyhalov 230d2d52addSAlexander Pyhalov case 'c': /* POSIX: write count */ 231d2d52addSAlexander Pyhalov cflag++; 2323ed621bcSAlexander Eremin break; 233d2d52addSAlexander Pyhalov 234d2d52addSAlexander Pyhalov case 'i': /* POSIX: ignore case */ 235d2d52addSAlexander Pyhalov iflag++; 236d2d52addSAlexander Pyhalov regflags |= REG_ICASE; 2377c478bd9Sstevel@tonic-gate 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; 2507c478bd9Sstevel@tonic-gate break; 251d2d52addSAlexander Pyhalov 252d2d52addSAlexander Pyhalov case 'n': /* POSIX: Write line numbers */ 2537c478bd9Sstevel@tonic-gate nflag++; 2547c478bd9Sstevel@tonic-gate break; 255d2d52addSAlexander Pyhalov 256d2d52addSAlexander Pyhalov case 'r': /* Solaris: search recursively */ 257e52fb54bSAlexander Eremin rflag++; 258e52fb54bSAlexander Eremin break; 259d2d52addSAlexander Pyhalov 260d2d52addSAlexander Pyhalov case 'b': /* Solaris: Write file block numbers */ 2617c478bd9Sstevel@tonic-gate bflag++; 2627c478bd9Sstevel@tonic-gate break; 263d2d52addSAlexander Pyhalov 264d2d52addSAlexander Pyhalov case 's': /* POSIX: No error msgs for files */ 2657c478bd9Sstevel@tonic-gate sflag++; 2667c478bd9Sstevel@tonic-gate 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; 2797c478bd9Sstevel@tonic-gate 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; 2937c478bd9Sstevel@tonic-gate break; 294d2d52addSAlexander Pyhalov 295d2d52addSAlexander Pyhalov /* 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; 299d2d52addSAlexander Pyhalov break; 3004adc6f15SPeter Tribble /* Solaris: precede every match with file name */ 301d2d52addSAlexander Pyhalov case 'H': 302d2d52addSAlexander Pyhalov Hflag = 1; 303d2d52addSAlexander Pyhalov hflag = 0; 304d2d52addSAlexander Pyhalov break; 305d2d52addSAlexander Pyhalov 306d2d52addSAlexander Pyhalov case 'q': /* POSIX: quiet: status only */ 307d2d52addSAlexander Pyhalov qflag++; 308d2d52addSAlexander Pyhalov break; 309d2d52addSAlexander Pyhalov 310d2d52addSAlexander Pyhalov case 'w': /* Solaris: treat pattern as word */ 3117c478bd9Sstevel@tonic-gate wflag++; 3127c478bd9Sstevel@tonic-gate break; 313d2d52addSAlexander Pyhalov 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); 342d2d52addSAlexander Pyhalov exit(2); 343d2d52addSAlexander Pyhalov } 344d2d52addSAlexander Pyhalov if (conalen) 345d2d52addSAlexander Pyhalov conflag |= AFTER; 346d2d52addSAlexander Pyhalov 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; 383d2d52addSAlexander Pyhalov 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(); 3947c478bd9Sstevel@tonic-gate } 395d2d52addSAlexander Pyhalov } 396d2d52addSAlexander Pyhalov /* 397d2d52addSAlexander Pyhalov * If we're invoked as egrep or fgrep we need to do some checks 398d2d52addSAlexander Pyhalov */ 3997c478bd9Sstevel@tonic-gate 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++; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 425d2d52addSAlexander Pyhalov if (wflag && (Eflag || Fflag)) { 426d2d52addSAlexander Pyhalov /* 427d2d52addSAlexander Pyhalov * -w cannot be specified with grep -F 428d2d52addSAlexander Pyhalov */ 429d2d52addSAlexander Pyhalov usage(); 430d2d52addSAlexander Pyhalov } 4317c478bd9Sstevel@tonic-gate 432d2d52addSAlexander Pyhalov /* 433d2d52addSAlexander Pyhalov * -E and -F flags are mutually exclusive - check for this 434d2d52addSAlexander Pyhalov */ 435d2d52addSAlexander Pyhalov if (Eflag && Fflag) 436d2d52addSAlexander Pyhalov usage(); 4377c478bd9Sstevel@tonic-gate 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 } 4797c478bd9Sstevel@tonic-gate 480d2d52addSAlexander Pyhalov argv += optind - 1; 481d2d52addSAlexander Pyhalov argc -= optind - 1; 4827c478bd9Sstevel@tonic-gate 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]); 4957c478bd9Sstevel@tonic-gate } 496d2d52addSAlexander Pyhalov free(file_list); 497d2d52addSAlexander Pyhalov } 4987c478bd9Sstevel@tonic-gate 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++; 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 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 */ 5327c478bd9Sstevel@tonic-gate 533d2d52addSAlexander Pyhalov (void) fflush(stdout); 5347c478bd9Sstevel@tonic-gate 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 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 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 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); 6297c478bd9Sstevel@tonic-gate 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 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; 6877c478bd9Sstevel@tonic-gate } 688d2d52addSAlexander Pyhalov if (bufp[buflen - 1] == '\n') { 689d2d52addSAlexander Pyhalov bufp[--buflen] = '\0'; 6907c478bd9Sstevel@tonic-gate } 691d2d52addSAlexander Pyhalov addpattern(inbuf); 692d2d52addSAlexander Pyhalov 693d2d52addSAlexander Pyhalov bufp = inbuf; 694d2d52addSAlexander Pyhalov bufused = 0; 6957c478bd9Sstevel@tonic-gate } 696d2d52addSAlexander Pyhalov free(inbuf); 697d2d52addSAlexander Pyhalov free(prntbuf); 698d2d52addSAlexander Pyhalov free(conbuf); 699d2d52addSAlexander Pyhalov (void) fclose(fp); 700d2d52addSAlexander Pyhalov } 7017c478bd9Sstevel@tonic-gate 702d2d52addSAlexander Pyhalov /* 703d2d52addSAlexander Pyhalov * Add a string to the pattern list. 704d2d52addSAlexander Pyhalov */ 705d2d52addSAlexander Pyhalov static void 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; 7557c478bd9Sstevel@tonic-gate } 756d2d52addSAlexander Pyhalov } 757d2d52addSAlexander Pyhalov 758*dbe930bfSRobert Mustacchi /* 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 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 803d2d52addSAlexander Pyhalov /* 804d2d52addSAlexander Pyhalov * Fix patterns. 805d2d52addSAlexander Pyhalov * Must do after all arguments read, in case later -i option. 806d2d52addSAlexander Pyhalov */ 807d2d52addSAlexander Pyhalov static 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 } 8367c478bd9Sstevel@tonic-gate 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; 8467c478bd9Sstevel@tonic-gate 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; 8637c478bd9Sstevel@tonic-gate } 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 * 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 * 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 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 */ 9314adc6f15SPeter Tribble 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)); 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate 952d2d52addSAlexander Pyhalov 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); 958d2d52addSAlexander Pyhalov } 959d2d52addSAlexander Pyhalov } 960d2d52addSAlexander Pyhalov 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 } 968d2d52addSAlexander Pyhalov } 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; 976d2d52addSAlexander Pyhalov 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; 983d2d52addSAlexander Pyhalov 984d2d52addSAlexander Pyhalov if (data_len == 0) { 985d2d52addSAlexander Pyhalov /* 986d2d52addSAlexander Pyhalov * If no data in the buffer, reset ptr 987d2d52addSAlexander Pyhalov */ 988d2d52addSAlexander Pyhalov ptr = prntbuf; 989d2d52addSAlexander Pyhalov if (conflag != 0 && conptr == NULL) { 990d2d52addSAlexander Pyhalov conptr = conbuf; 991d2d52addSAlexander Pyhalov conptrend = conptr - 1; 992d2d52addSAlexander Pyhalov } 993d2d52addSAlexander Pyhalov } 994d2d52addSAlexander Pyhalov if (ptr == prntbuf) { 9957c478bd9Sstevel@tonic-gate /* 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. 10007c478bd9Sstevel@tonic-gate */ 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; 1018d2d52addSAlexander Pyhalov 1019d2d52addSAlexander Pyhalov if (data_len == 0) { 1020d2d52addSAlexander Pyhalov /* 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; 1026d2d52addSAlexander Pyhalov } else { 1027d2d52addSAlexander Pyhalov goto out; 1028d2d52addSAlexander Pyhalov } 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 */ 10467c478bd9Sstevel@tonic-gate 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); 10547c478bd9Sstevel@tonic-gate } 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: 10817c478bd9Sstevel@tonic-gate 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) { 10947c478bd9Sstevel@tonic-gate /* 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. 10997c478bd9Sstevel@tonic-gate */ 1100d2d52addSAlexander Pyhalov char *bline; 1101d2d52addSAlexander Pyhalov bline = bmgexec(ptr, ptr + data_len); 1102d2d52addSAlexander Pyhalov if (bline == NULL) { 11037c478bd9Sstevel@tonic-gate /* 1104d2d52addSAlexander Pyhalov * No pattern found in this chunk. 1105d2d52addSAlexander Pyhalov * Need to find the last line 1106d2d52addSAlexander Pyhalov * in this chunk. 11077c478bd9Sstevel@tonic-gate */ 1108d2d52addSAlexander Pyhalov ptrend = rfind_nl(ptr, data_len); 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 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. 11297c478bd9Sstevel@tonic-gate */ 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 */ 1137d2d52addSAlexander Pyhalov *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) { 116081dd18d8SRobert Mustacchi 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 */ 117681dd18d8SRobert Mustacchi for (pp = patterns; pp; pp = pp->next) { 117781dd18d8SRobert Mustacchi int rv; 117881dd18d8SRobert Mustacchi regmatch_t rm; 117981dd18d8SRobert Mustacchi size_t nmatch = 0; 11807c478bd9Sstevel@tonic-gate 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; 11927c478bd9Sstevel@tonic-gate 119381dd18d8SRobert Mustacchi rv = regexec(&pp->re, ptr, nmatch, &rm, 0); 119481dd18d8SRobert Mustacchi 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; 1204d2d52addSAlexander Pyhalov } 12057c478bd9Sstevel@tonic-gate 120681dd18d8SRobert Mustacchi /* matched */ 120781dd18d8SRobert Mustacchi if (oflag) { 120881dd18d8SRobert Mustacchi startmatch = ptr + rm.rm_so; 120981dd18d8SRobert Mustacchi postmatch = ptr + rm.rm_eo; 1210d2d52addSAlexander Pyhalov } 121181dd18d8SRobert Mustacchi break; 1212d2d52addSAlexander Pyhalov } 1213d2d52addSAlexander Pyhalov 121481dd18d8SRobert Mustacchi switch (rv) { 121581dd18d8SRobert Mustacchi case REG_NOMATCH: 121681dd18d8SRobert Mustacchi break; 121781dd18d8SRobert Mustacchi case REG_ECHAR: 121881dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext( 1219d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: invalid multibyte character\n"), 122081dd18d8SRobert Mustacchi cmdname, fn, lineno); 122181dd18d8SRobert Mustacchi break; 122281dd18d8SRobert Mustacchi default: 122381dd18d8SRobert Mustacchi (void) regerror(rv, &pp->re, errstr, 122481dd18d8SRobert Mustacchi sizeof (errstr)); 122581dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext( 1226d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: %s\n"), 122781dd18d8SRobert Mustacchi cmdname, fn, lineno, errstr); 122881dd18d8SRobert Mustacchi exit(2); 1229d2d52addSAlexander Pyhalov } 1230d2d52addSAlexander Pyhalov } 1231d2d52addSAlexander Pyhalov 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); 1276d2d52addSAlexander Pyhalov exit(2); 1277d2d52addSAlexander Pyhalov } 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 { 139881dd18d8SRobert Mustacchi prntptr = ptr; 139981dd18d8SRobert Mustacchi } 1400d2d52addSAlexander Pyhalov 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; 14097c478bd9Sstevel@tonic-gate } else { 1410d2d52addSAlexander Pyhalov /* No match, or we're not done building context */ 1411d2d52addSAlexander Pyhalov goto L_skip_line; 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 141481dd18d8SRobert Mustacchi if (oflag) { 141581dd18d8SRobert Mustacchi prntptrend = postmatch - 1; 141681dd18d8SRobert Mustacchi } else { 141781dd18d8SRobert Mustacchi prntptrend = prntptr - 1; 141881dd18d8SRobert Mustacchi } 141981dd18d8SRobert Mustacchi while (oflag || (prntptrend = find_nl(prntptrend + 1, 1420d2d52addSAlexander Pyhalov prntlen)) != NULL) { 14217c478bd9Sstevel@tonic-gate /* 1422d2d52addSAlexander Pyhalov * GNU grep uses '-' for context lines and ':' for 1423d2d52addSAlexander Pyhalov * matching lines, so replicate that here. 14247c478bd9Sstevel@tonic-gate */ 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 14377c478bd9Sstevel@tonic-gate /* 1438d2d52addSAlexander Pyhalov * Handle q, l, and c flags. 14397c478bd9Sstevel@tonic-gate */ 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 } 14947c478bd9Sstevel@tonic-gate 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 } 15247c478bd9Sstevel@tonic-gate 1525d2d52addSAlexander Pyhalov L_skip_line: 1526d2d52addSAlexander Pyhalov if (!newlinep) 15277c478bd9Sstevel@tonic-gate break; 15287c478bd9Sstevel@tonic-gate 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; 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 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 } 15487c478bd9Sstevel@tonic-gate } 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); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 1566d2d52addSAlexander Pyhalov /* 1567d2d52addSAlexander Pyhalov * usage message for grep 1568d2d52addSAlexander Pyhalov */ 1569d2d52addSAlexander Pyhalov static void 1570d2d52addSAlexander Pyhalov usage(void) 15717c478bd9Sstevel@tonic-gate { 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 } 15817c478bd9Sstevel@tonic-gate 1582d2d52addSAlexander Pyhalov /* 1583d2d52addSAlexander Pyhalov * Compile literal pattern into BMG tables 1584d2d52addSAlexander Pyhalov */ 1585d2d52addSAlexander Pyhalov static void 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; 15917c478bd9Sstevel@tonic-gate 1592d2d52addSAlexander Pyhalov bmglen = len; 1593d2d52addSAlexander Pyhalov bmgpat = pat; 15947c478bd9Sstevel@tonic-gate 1595d2d52addSAlexander Pyhalov for (i = 0; i < M_CSETSIZE; i++) { 1596d2d52addSAlexander Pyhalov bmgtab[i] = len; 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate 1599d2d52addSAlexander Pyhalov len--; 1600d2d52addSAlexander Pyhalov for (tlen = len, i = 0; i <= len; i++, tlen--) { 1601d2d52addSAlexander Pyhalov bmgtab[*uc++] = tlen; 1602d2d52addSAlexander Pyhalov } 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate 1605d2d52addSAlexander Pyhalov /* 1606d2d52addSAlexander Pyhalov * BMG search. 1607d2d52addSAlexander Pyhalov */ 1608d2d52addSAlexander Pyhalov static char * 1609d2d52addSAlexander Pyhalov bmgexec(char *str, char *end) 16107c478bd9Sstevel@tonic-gate { 1611d2d52addSAlexander Pyhalov int t; 1612d2d52addSAlexander Pyhalov char *k, *s, *p; 16137c478bd9Sstevel@tonic-gate 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 */ 16347c478bd9Sstevel@tonic-gate } 1635