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. 42*2e5ac464SRobert 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> 627c478bd9Sstevel@tonic-gate 63d2d52addSAlexander Pyhalov #define STDIN_FILENAME gettext("(standard input)") 64d2d52addSAlexander Pyhalov 65d2d52addSAlexander Pyhalov #define BSIZE 512 /* Size of block for -b */ 66d2d52addSAlexander Pyhalov #define BUFSIZE 8192 /* Input buffer size */ 67d2d52addSAlexander Pyhalov #define MAX_DEPTH 1000 /* how deep to recurse */ 68d2d52addSAlexander Pyhalov 694adc6f15SPeter Tribble #define AFTER 1 /* 'After' Context */ 704adc6f15SPeter Tribble #define BEFORE 2 /* 'Before' Context */ 71d2d52addSAlexander Pyhalov #define CONTEXT (AFTER|BEFORE) /* Full Context */ 72d2d52addSAlexander Pyhalov 73d2d52addSAlexander Pyhalov #define M_CSETSIZE 256 /* singlebyte chars */ 74d2d52addSAlexander Pyhalov static int bmglen; /* length of BMG pattern */ 75d2d52addSAlexander Pyhalov static char *bmgpat; /* BMG pattern */ 76d2d52addSAlexander Pyhalov static int bmgtab[M_CSETSIZE]; /* BMG delta1 table */ 77d2d52addSAlexander Pyhalov 78d2d52addSAlexander Pyhalov typedef struct _PATTERN { 79d2d52addSAlexander Pyhalov char *pattern; /* original pattern */ 80d2d52addSAlexander Pyhalov wchar_t *wpattern; /* wide, lowercased 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 */ 98*2e5ac464SRobert 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 */ 111d2d52addSAlexander Pyhalov static char *cmdname; 112d2d52addSAlexander Pyhalov 113d2d52addSAlexander Pyhalov static int use_wchar, use_bmg, mblocale; 114d2d52addSAlexander Pyhalov 115d2d52addSAlexander Pyhalov static size_t outbuflen, prntbuflen, conbuflen; 1164adc6f15SPeter Tribble static unsigned long conalen, conblen, conmatches; 117d2d52addSAlexander Pyhalov static char *prntbuf, *conbuf; 118d2d52addSAlexander Pyhalov static wchar_t *outline; 119d2d52addSAlexander Pyhalov 120d2d52addSAlexander Pyhalov static void addfile(const char *fn); 121d2d52addSAlexander Pyhalov static void addpattern(char *s); 122d2d52addSAlexander Pyhalov static void fixpatterns(void); 123d2d52addSAlexander Pyhalov static void usage(void); 124d2d52addSAlexander Pyhalov static int grep(int, const char *); 125d2d52addSAlexander Pyhalov static void bmgcomp(char *, int); 126d2d52addSAlexander Pyhalov static char *bmgexec(char *, char *); 127e52fb54bSAlexander Eremin static int recursive(const char *, const struct stat *, int, struct FTW *); 128d2d52addSAlexander Pyhalov static void process_path(const char *); 129d2d52addSAlexander Pyhalov static void process_file(const char *, int); 1307c478bd9Sstevel@tonic-gate 131d2d52addSAlexander Pyhalov /* 132d2d52addSAlexander Pyhalov * mainline for grep 133d2d52addSAlexander Pyhalov */ 1347c478bd9Sstevel@tonic-gate int 13555f91622Sceastha main(int argc, char **argv) 1367c478bd9Sstevel@tonic-gate { 137d2d52addSAlexander Pyhalov char *ap, *test; 1387c478bd9Sstevel@tonic-gate int c; 139d2d52addSAlexander Pyhalov int fflag = 0; 140d2d52addSAlexander Pyhalov int i, n_pattern = 0, n_file = 0; 141d2d52addSAlexander Pyhalov char **pattern_list = NULL; 142d2d52addSAlexander Pyhalov char **file_list = NULL; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1457c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 146d2d52addSAlexander Pyhalov #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1477c478bd9Sstevel@tonic-gate #endif 1487c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1497c478bd9Sstevel@tonic-gate 150d2d52addSAlexander Pyhalov /* 151d2d52addSAlexander Pyhalov * true if this is running on the multibyte locale 152d2d52addSAlexander Pyhalov */ 153d2d52addSAlexander Pyhalov mblocale = (MB_CUR_MAX > 1); 154d2d52addSAlexander Pyhalov /* 155d2d52addSAlexander Pyhalov * Skip leading slashes 156d2d52addSAlexander Pyhalov */ 157d2d52addSAlexander Pyhalov cmdname = argv[0]; 158d2d52addSAlexander Pyhalov if (ap = strrchr(cmdname, '/')) 159d2d52addSAlexander Pyhalov cmdname = ap + 1; 160d2d52addSAlexander Pyhalov 161d2d52addSAlexander Pyhalov ap = cmdname; 162d2d52addSAlexander Pyhalov /* 163d2d52addSAlexander Pyhalov * Detect egrep/fgrep via command name, map to -E and -F options. 164d2d52addSAlexander Pyhalov */ 165d2d52addSAlexander Pyhalov if (*ap == 'e' || *ap == 'E') { 166d2d52addSAlexander Pyhalov regflags |= REG_EXTENDED; 167d2d52addSAlexander Pyhalov egrep++; 168d2d52addSAlexander Pyhalov } else { 169d2d52addSAlexander Pyhalov if (*ap == 'f' || *ap == 'F') { 170d2d52addSAlexander Pyhalov fgrep++; 171d2d52addSAlexander Pyhalov } 172d2d52addSAlexander Pyhalov } 173d2d52addSAlexander Pyhalov 174d2d52addSAlexander Pyhalov /* check for non-standard "-line-count" option */ 175d2d52addSAlexander Pyhalov for (i = 1; i < argc; i++) { 176d2d52addSAlexander Pyhalov if (strcmp(argv[i], "--") == 0) 17741599e9fSDamian Bogel break; 178d2d52addSAlexander Pyhalov 179d2d52addSAlexander Pyhalov /* isdigit() check prevents negative arguments */ 180d2d52addSAlexander Pyhalov if ((argv[i][0] == '-') && isdigit(argv[i][1])) { 181d2d52addSAlexander Pyhalov if (strlen(&argv[i][1]) != 182d2d52addSAlexander Pyhalov strspn(&argv[i][1], "0123456789")) { 183d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 184d2d52addSAlexander Pyhalov "%s: Bad number flag\n"), argv[0]); 185d2d52addSAlexander Pyhalov usage(); 186d2d52addSAlexander Pyhalov } 187d2d52addSAlexander Pyhalov 188d2d52addSAlexander Pyhalov errno = 0; 189d2d52addSAlexander Pyhalov conalen = conblen = strtoul(&argv[i][1], (char **)NULL, 190d2d52addSAlexander Pyhalov 10); 191d2d52addSAlexander Pyhalov 192d2d52addSAlexander Pyhalov if (errno != 0 || conalen >= ULONG_MAX) { 193d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 194d2d52addSAlexander Pyhalov "%s: Bad context argument\n"), argv[0]); 195d2d52addSAlexander Pyhalov } else if (conalen) 196d2d52addSAlexander Pyhalov conflag = CONTEXT; 197d2d52addSAlexander Pyhalov 198d2d52addSAlexander Pyhalov while (i < argc) { 199d2d52addSAlexander Pyhalov argv[i] = argv[i + 1]; 200d2d52addSAlexander Pyhalov i++; 201d2d52addSAlexander Pyhalov } 202d2d52addSAlexander Pyhalov argc--; 203d2d52addSAlexander Pyhalov } 204d2d52addSAlexander Pyhalov } 205d2d52addSAlexander Pyhalov 206*2e5ac464SRobert Mustacchi while ((c = getopt(argc, argv, "vwchHilLnrbse:f:qxEFIRA:B:C:")) != 207*2e5ac464SRobert Mustacchi EOF) { 208d2d52addSAlexander Pyhalov unsigned long tval; 209d2d52addSAlexander Pyhalov switch (c) { 210d2d52addSAlexander Pyhalov case 'v': /* POSIX: negate matches */ 211d2d52addSAlexander Pyhalov nvflag = B_FALSE; 2127c478bd9Sstevel@tonic-gate break; 213d2d52addSAlexander Pyhalov 214d2d52addSAlexander Pyhalov case 'c': /* POSIX: write count */ 215d2d52addSAlexander Pyhalov cflag++; 2163ed621bcSAlexander Eremin break; 217d2d52addSAlexander Pyhalov 218d2d52addSAlexander Pyhalov case 'i': /* POSIX: ignore case */ 219d2d52addSAlexander Pyhalov iflag++; 220d2d52addSAlexander Pyhalov regflags |= REG_ICASE; 2217c478bd9Sstevel@tonic-gate break; 222d2d52addSAlexander Pyhalov 223*2e5ac464SRobert Mustacchi /* 224*2e5ac464SRobert Mustacchi * The last of -l and -L are honored. 225*2e5ac464SRobert Mustacchi */ 226d2d52addSAlexander Pyhalov case 'l': /* POSIX: Write filenames only */ 227d2d52addSAlexander Pyhalov lflag++; 228*2e5ac464SRobert Mustacchi Lflag = 0; 229*2e5ac464SRobert Mustacchi break; 230*2e5ac464SRobert Mustacchi 231*2e5ac464SRobert Mustacchi case 'L': /* Write non-matching filenames */ 232*2e5ac464SRobert Mustacchi Lflag++; 233*2e5ac464SRobert Mustacchi lflag = 0; 2347c478bd9Sstevel@tonic-gate break; 235d2d52addSAlexander Pyhalov 236d2d52addSAlexander Pyhalov case 'n': /* POSIX: Write line numbers */ 2377c478bd9Sstevel@tonic-gate nflag++; 2387c478bd9Sstevel@tonic-gate break; 239d2d52addSAlexander Pyhalov 240d2d52addSAlexander Pyhalov case 'r': /* Solaris: search recursively */ 241e52fb54bSAlexander Eremin rflag++; 242e52fb54bSAlexander Eremin break; 243d2d52addSAlexander Pyhalov 244d2d52addSAlexander Pyhalov case 'b': /* Solaris: Write file block numbers */ 2457c478bd9Sstevel@tonic-gate bflag++; 2467c478bd9Sstevel@tonic-gate break; 247d2d52addSAlexander Pyhalov 248d2d52addSAlexander Pyhalov case 's': /* POSIX: No error msgs for files */ 2497c478bd9Sstevel@tonic-gate sflag++; 2507c478bd9Sstevel@tonic-gate break; 251d2d52addSAlexander Pyhalov 252d2d52addSAlexander Pyhalov case 'e': /* POSIX: pattern list */ 253d2d52addSAlexander Pyhalov n_pattern++; 254d2d52addSAlexander Pyhalov pattern_list = realloc(pattern_list, 255d2d52addSAlexander Pyhalov sizeof (char *) * n_pattern); 256d2d52addSAlexander Pyhalov if (pattern_list == NULL) { 257d2d52addSAlexander Pyhalov (void) fprintf(stderr, 258d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 259d2d52addSAlexander Pyhalov cmdname); 260d2d52addSAlexander Pyhalov exit(2); 261d2d52addSAlexander Pyhalov } 262d2d52addSAlexander Pyhalov *(pattern_list + n_pattern - 1) = optarg; 2637c478bd9Sstevel@tonic-gate break; 264d2d52addSAlexander Pyhalov 265d2d52addSAlexander Pyhalov case 'f': /* POSIX: pattern file */ 266d2d52addSAlexander Pyhalov fflag = 1; 267d2d52addSAlexander Pyhalov n_file++; 268d2d52addSAlexander Pyhalov file_list = realloc(file_list, 269d2d52addSAlexander Pyhalov sizeof (char *) * n_file); 270d2d52addSAlexander Pyhalov if (file_list == NULL) { 271d2d52addSAlexander Pyhalov (void) fprintf(stderr, 272d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 273d2d52addSAlexander Pyhalov cmdname); 274d2d52addSAlexander Pyhalov exit(2); 275d2d52addSAlexander Pyhalov } 276d2d52addSAlexander Pyhalov *(file_list + n_file - 1) = optarg; 2777c478bd9Sstevel@tonic-gate break; 278d2d52addSAlexander Pyhalov 279d2d52addSAlexander Pyhalov /* based on options order h or H is set as in GNU grep */ 2804adc6f15SPeter Tribble case 'h': /* Solaris: suppress printing of file name */ 281d2d52addSAlexander Pyhalov hflag = 1; 282d2d52addSAlexander Pyhalov Hflag = 0; 283d2d52addSAlexander Pyhalov break; 2844adc6f15SPeter Tribble /* Solaris: precede every match with file name */ 285d2d52addSAlexander Pyhalov case 'H': 286d2d52addSAlexander Pyhalov Hflag = 1; 287d2d52addSAlexander Pyhalov hflag = 0; 288d2d52addSAlexander Pyhalov break; 289d2d52addSAlexander Pyhalov 290d2d52addSAlexander Pyhalov case 'q': /* POSIX: quiet: status only */ 291d2d52addSAlexander Pyhalov qflag++; 292d2d52addSAlexander Pyhalov break; 293d2d52addSAlexander Pyhalov 294d2d52addSAlexander Pyhalov case 'w': /* Solaris: treat pattern as word */ 2957c478bd9Sstevel@tonic-gate wflag++; 2967c478bd9Sstevel@tonic-gate break; 297d2d52addSAlexander Pyhalov 298d2d52addSAlexander Pyhalov case 'x': /* POSIX: full line matches */ 299d2d52addSAlexander Pyhalov xflag++; 300d2d52addSAlexander Pyhalov break; 301d2d52addSAlexander Pyhalov 302d2d52addSAlexander Pyhalov case 'E': /* POSIX: Extended RE's */ 303d2d52addSAlexander Pyhalov regflags |= REG_EXTENDED; 304d2d52addSAlexander Pyhalov Eflag++; 305d2d52addSAlexander Pyhalov break; 306d2d52addSAlexander Pyhalov 307d2d52addSAlexander Pyhalov case 'F': /* POSIX: strings, not RE's */ 308d2d52addSAlexander Pyhalov Fflag++; 309d2d52addSAlexander Pyhalov break; 310d2d52addSAlexander Pyhalov 311d2d52addSAlexander Pyhalov case 'R': /* Solaris: like rflag, but follow symlinks */ 312d2d52addSAlexander Pyhalov Rflag++; 313d2d52addSAlexander Pyhalov rflag++; 314d2d52addSAlexander Pyhalov break; 315d2d52addSAlexander Pyhalov 316d2d52addSAlexander Pyhalov case 'A': /* print N lines after each match */ 317d2d52addSAlexander Pyhalov errno = 0; 318d2d52addSAlexander Pyhalov conalen = strtoul(optarg, &test, 10); 319d2d52addSAlexander Pyhalov /* *test will be non-null if optarg is negative */ 320d2d52addSAlexander Pyhalov if (errno != 0 || *test != '\0' || 321d2d52addSAlexander Pyhalov conalen >= ULONG_MAX) { 322d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 323d2d52addSAlexander Pyhalov "%s: Bad context argument: %s\n"), 324d2d52addSAlexander Pyhalov argv[0], optarg); 325d2d52addSAlexander Pyhalov exit(2); 326d2d52addSAlexander Pyhalov } 327d2d52addSAlexander Pyhalov if (conalen) 328d2d52addSAlexander Pyhalov conflag |= AFTER; 329d2d52addSAlexander Pyhalov else 330d2d52addSAlexander Pyhalov conflag &= ~AFTER; 331d2d52addSAlexander Pyhalov break; 332d2d52addSAlexander Pyhalov case 'B': /* print N lines before each match */ 333d2d52addSAlexander Pyhalov errno = 0; 334d2d52addSAlexander Pyhalov conblen = strtoul(optarg, &test, 10); 335d2d52addSAlexander Pyhalov /* *test will be non-null if optarg is negative */ 336d2d52addSAlexander Pyhalov if (errno != 0 || *test != '\0' || 337d2d52addSAlexander Pyhalov conblen >= ULONG_MAX) { 338d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 339d2d52addSAlexander Pyhalov "%s: Bad context argument: %s\n"), 340d2d52addSAlexander Pyhalov argv[0], optarg); 341d2d52addSAlexander Pyhalov exit(2); 342d2d52addSAlexander Pyhalov } 343d2d52addSAlexander Pyhalov if (conblen) 344d2d52addSAlexander Pyhalov conflag |= BEFORE; 345d2d52addSAlexander Pyhalov else 346d2d52addSAlexander Pyhalov conflag &= ~BEFORE; 347d2d52addSAlexander Pyhalov break; 348d2d52addSAlexander Pyhalov case 'C': /* print N lines around each match */ 349d2d52addSAlexander Pyhalov errno = 0; 350d2d52addSAlexander Pyhalov tval = strtoul(optarg, &test, 10); 351d2d52addSAlexander Pyhalov /* *test will be non-null if optarg is negative */ 352d2d52addSAlexander Pyhalov if (errno != 0 || *test != '\0' || tval >= ULONG_MAX) { 353d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 354d2d52addSAlexander Pyhalov "%s: Bad context argument: %s\n"), 355d2d52addSAlexander Pyhalov argv[0], optarg); 356d2d52addSAlexander Pyhalov exit(2); 357d2d52addSAlexander Pyhalov } 358d2d52addSAlexander Pyhalov if (tval) { 359d2d52addSAlexander Pyhalov if ((conflag & BEFORE) == 0) 360d2d52addSAlexander Pyhalov conblen = tval; 361d2d52addSAlexander Pyhalov if ((conflag & AFTER) == 0) 362d2d52addSAlexander Pyhalov conalen = tval; 363d2d52addSAlexander Pyhalov conflag = CONTEXT; 364d2d52addSAlexander Pyhalov } 365d2d52addSAlexander Pyhalov break; 366d2d52addSAlexander Pyhalov 367d2d52addSAlexander Pyhalov default: 368d2d52addSAlexander Pyhalov usage(); 3697c478bd9Sstevel@tonic-gate } 370d2d52addSAlexander Pyhalov } 371d2d52addSAlexander Pyhalov /* 372d2d52addSAlexander Pyhalov * If we're invoked as egrep or fgrep we need to do some checks 373d2d52addSAlexander Pyhalov */ 3747c478bd9Sstevel@tonic-gate 375d2d52addSAlexander Pyhalov if (egrep || fgrep) { 376d2d52addSAlexander Pyhalov /* 377d2d52addSAlexander Pyhalov * Use of -E or -F with egrep or fgrep is illegal 378d2d52addSAlexander Pyhalov */ 379d2d52addSAlexander Pyhalov if (Eflag || Fflag) 380d2d52addSAlexander Pyhalov usage(); 381d2d52addSAlexander Pyhalov /* 382d2d52addSAlexander Pyhalov * Don't allow use of wflag with egrep / fgrep 383d2d52addSAlexander Pyhalov */ 384d2d52addSAlexander Pyhalov if (wflag) 385d2d52addSAlexander Pyhalov usage(); 386d2d52addSAlexander Pyhalov /* 387d2d52addSAlexander Pyhalov * For Solaris the -s flag is equivalent to XCU -q 388d2d52addSAlexander Pyhalov */ 389d2d52addSAlexander Pyhalov if (sflag) 390d2d52addSAlexander Pyhalov qflag++; 391d2d52addSAlexander Pyhalov /* 392d2d52addSAlexander Pyhalov * done with above checks - set the appropriate flags 393d2d52addSAlexander Pyhalov */ 394d2d52addSAlexander Pyhalov if (egrep) 395d2d52addSAlexander Pyhalov Eflag++; 396d2d52addSAlexander Pyhalov else /* Else fgrep */ 397d2d52addSAlexander Pyhalov Fflag++; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 400d2d52addSAlexander Pyhalov if (wflag && (Eflag || Fflag)) { 401d2d52addSAlexander Pyhalov /* 402d2d52addSAlexander Pyhalov * -w cannot be specified with grep -F 403d2d52addSAlexander Pyhalov */ 404d2d52addSAlexander Pyhalov usage(); 405d2d52addSAlexander Pyhalov } 4067c478bd9Sstevel@tonic-gate 407d2d52addSAlexander Pyhalov /* 408d2d52addSAlexander Pyhalov * -E and -F flags are mutually exclusive - check for this 409d2d52addSAlexander Pyhalov */ 410d2d52addSAlexander Pyhalov if (Eflag && Fflag) 411d2d52addSAlexander Pyhalov usage(); 4127c478bd9Sstevel@tonic-gate 413d2d52addSAlexander Pyhalov /* 414*2e5ac464SRobert Mustacchi * -l or -L overrides -H like in GNU grep 415d2d52addSAlexander Pyhalov */ 416*2e5ac464SRobert Mustacchi if (lflag || Lflag) 417d2d52addSAlexander Pyhalov Hflag = 0; 418d2d52addSAlexander Pyhalov 419d2d52addSAlexander Pyhalov /* 420d2d52addSAlexander Pyhalov * -c, -l and -q flags are mutually exclusive 421d2d52addSAlexander Pyhalov * We have -c override -l like in Solaris. 422d2d52addSAlexander Pyhalov * -q overrides -l & -c programmatically in grep() function. 423d2d52addSAlexander Pyhalov */ 424*2e5ac464SRobert Mustacchi if (cflag && (lflag || Lflag)) { 425d2d52addSAlexander Pyhalov lflag = 0; 426*2e5ac464SRobert Mustacchi Lflag = 0; 427*2e5ac464SRobert Mustacchi } 4287c478bd9Sstevel@tonic-gate 429d2d52addSAlexander Pyhalov argv += optind - 1; 430d2d52addSAlexander Pyhalov argc -= optind - 1; 4317c478bd9Sstevel@tonic-gate 432d2d52addSAlexander Pyhalov /* 433d2d52addSAlexander Pyhalov * Now handling -e and -f option 434d2d52addSAlexander Pyhalov */ 435d2d52addSAlexander Pyhalov if (pattern_list) { 436d2d52addSAlexander Pyhalov for (i = 0; i < n_pattern; i++) { 437d2d52addSAlexander Pyhalov addpattern(pattern_list[i]); 438d2d52addSAlexander Pyhalov } 439d2d52addSAlexander Pyhalov free(pattern_list); 440d2d52addSAlexander Pyhalov } 441d2d52addSAlexander Pyhalov if (file_list) { 442d2d52addSAlexander Pyhalov for (i = 0; i < n_file; i++) { 443d2d52addSAlexander Pyhalov addfile(file_list[i]); 4447c478bd9Sstevel@tonic-gate } 445d2d52addSAlexander Pyhalov free(file_list); 446d2d52addSAlexander Pyhalov } 4477c478bd9Sstevel@tonic-gate 448d2d52addSAlexander Pyhalov /* 449d2d52addSAlexander Pyhalov * No -e or -f? Make sure there is one more arg, use it as the pattern. 450d2d52addSAlexander Pyhalov */ 451d2d52addSAlexander Pyhalov if (patterns == NULL && !fflag) { 452d2d52addSAlexander Pyhalov if (argc < 2) 453d2d52addSAlexander Pyhalov usage(); 454d2d52addSAlexander Pyhalov addpattern(argv[1]); 455d2d52addSAlexander Pyhalov argc--; 456d2d52addSAlexander Pyhalov argv++; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 459d2d52addSAlexander Pyhalov /* 460d2d52addSAlexander Pyhalov * If -x flag is not specified or -i flag is specified 461d2d52addSAlexander Pyhalov * with fgrep in a multibyte locale, need to use 462d2d52addSAlexander Pyhalov * the wide character APIs. Otherwise, byte-oriented 463d2d52addSAlexander Pyhalov * process will be done. 464d2d52addSAlexander Pyhalov */ 465d2d52addSAlexander Pyhalov use_wchar = Fflag && mblocale && (!xflag || iflag); 466d2d52addSAlexander Pyhalov 467d2d52addSAlexander Pyhalov /* 468d2d52addSAlexander Pyhalov * Compile Patterns and also decide if BMG can be used 469d2d52addSAlexander Pyhalov */ 470d2d52addSAlexander Pyhalov fixpatterns(); 471d2d52addSAlexander Pyhalov 472d2d52addSAlexander Pyhalov /* Process all files: stdin, or rest of arg list */ 473d2d52addSAlexander Pyhalov if (argc < 2) { 474d2d52addSAlexander Pyhalov matched = grep(0, STDIN_FILENAME); 475d2d52addSAlexander Pyhalov } else { 476d2d52addSAlexander Pyhalov if (Hflag || (argc > 2 && hflag == 0)) 477d2d52addSAlexander Pyhalov outfn = 1; /* Print filename on match line */ 478d2d52addSAlexander Pyhalov for (argv++; *argv != NULL; argv++) { 479d2d52addSAlexander Pyhalov process_path(*argv); 480d2d52addSAlexander Pyhalov } 481d2d52addSAlexander Pyhalov } 482d2d52addSAlexander Pyhalov /* 483d2d52addSAlexander Pyhalov * Return() here is used instead of exit 484d2d52addSAlexander Pyhalov */ 4857c478bd9Sstevel@tonic-gate 486d2d52addSAlexander Pyhalov (void) fflush(stdout); 4877c478bd9Sstevel@tonic-gate 488d2d52addSAlexander Pyhalov if (errors) 489d2d52addSAlexander Pyhalov return (2); 490d2d52addSAlexander Pyhalov return (matched ? 0 : 1); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate static void 494d2d52addSAlexander Pyhalov process_path(const char *path) 495e52fb54bSAlexander Eremin { 496e52fb54bSAlexander Eremin struct stat st; 497e52fb54bSAlexander Eremin int walkflags = FTW_CHDIR; 498e52fb54bSAlexander Eremin char *buf = NULL; 499e52fb54bSAlexander Eremin 500e52fb54bSAlexander Eremin if (rflag) { 501e52fb54bSAlexander Eremin if (stat(path, &st) != -1 && 502e52fb54bSAlexander Eremin (st.st_mode & S_IFMT) == S_IFDIR) { 5034adc6f15SPeter Tribble if (!hflag) 5044adc6f15SPeter Tribble outfn = 1; /* Print filename unless -h */ 505e52fb54bSAlexander Eremin 506e52fb54bSAlexander Eremin /* 507e52fb54bSAlexander Eremin * Add trailing slash if arg 508e52fb54bSAlexander Eremin * is directory, to resolve symlinks. 509e52fb54bSAlexander Eremin */ 510e52fb54bSAlexander Eremin if (path[strlen(path) - 1] != '/') { 511e52fb54bSAlexander Eremin (void) asprintf(&buf, "%s/", path); 512e52fb54bSAlexander Eremin if (buf != NULL) 513e52fb54bSAlexander Eremin path = buf; 514e52fb54bSAlexander Eremin } 515e52fb54bSAlexander Eremin 516e52fb54bSAlexander Eremin /* 517e52fb54bSAlexander Eremin * Search through subdirs if path is directory. 518e52fb54bSAlexander Eremin * Don't follow symlinks if Rflag is not set. 519e52fb54bSAlexander Eremin */ 520e52fb54bSAlexander Eremin if (!Rflag) 521e52fb54bSAlexander Eremin walkflags |= FTW_PHYS; 522e52fb54bSAlexander Eremin 523e52fb54bSAlexander Eremin if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) { 524e52fb54bSAlexander Eremin if (!sflag) 525d2d52addSAlexander Pyhalov (void) fprintf(stderr, 526d2d52addSAlexander Pyhalov gettext("%s: can't open \"%s\"\n"), 527d2d52addSAlexander Pyhalov cmdname, path); 528d2d52addSAlexander Pyhalov errors = 1; 529e52fb54bSAlexander Eremin } 530e52fb54bSAlexander Eremin return; 531e52fb54bSAlexander Eremin } 532e52fb54bSAlexander Eremin } 533d2d52addSAlexander Pyhalov process_file(path, 0); 534e52fb54bSAlexander Eremin } 535e52fb54bSAlexander Eremin 536d2d52addSAlexander Pyhalov /* 537d2d52addSAlexander Pyhalov * Read and process all files in directory recursively. 538d2d52addSAlexander Pyhalov */ 539e52fb54bSAlexander Eremin static int 540e52fb54bSAlexander Eremin recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw) 541e52fb54bSAlexander Eremin { 542e52fb54bSAlexander Eremin /* 543d2d52addSAlexander Pyhalov * Process files and follow symlinks if Rflag set. 544e52fb54bSAlexander Eremin */ 545e52fb54bSAlexander Eremin if (info != FTW_F) { 546d2d52addSAlexander Pyhalov /* Report broken symlinks and unreadable files */ 547e52fb54bSAlexander Eremin if (!sflag && 548e52fb54bSAlexander Eremin (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) { 549d2d52addSAlexander Pyhalov (void) fprintf(stderr, 550d2d52addSAlexander Pyhalov gettext("%s: can't open \"%s\"\n"), cmdname, name); 551e52fb54bSAlexander Eremin } 552e52fb54bSAlexander Eremin return (0); 553e52fb54bSAlexander Eremin } 554e52fb54bSAlexander Eremin 555d2d52addSAlexander Pyhalov 556d2d52addSAlexander Pyhalov /* Skip devices and pipes if Rflag is not set */ 557e52fb54bSAlexander Eremin if (!Rflag && !S_ISREG(statp->st_mode)) 558e52fb54bSAlexander Eremin return (0); 559d2d52addSAlexander Pyhalov /* Pass offset to relative name from FTW_CHDIR */ 560d2d52addSAlexander Pyhalov process_file(name, ftw->base); 561e52fb54bSAlexander Eremin return (0); 562e52fb54bSAlexander Eremin } 563e52fb54bSAlexander Eremin 564d2d52addSAlexander Pyhalov /* 565d2d52addSAlexander Pyhalov * Opens file and call grep function. 566d2d52addSAlexander Pyhalov */ 567e52fb54bSAlexander Eremin static void 568d2d52addSAlexander Pyhalov process_file(const char *name, int base) 5697c478bd9Sstevel@tonic-gate { 570d2d52addSAlexander Pyhalov int fd; 5717c478bd9Sstevel@tonic-gate 572d2d52addSAlexander Pyhalov if ((fd = open(name + base, O_RDONLY)) == -1) { 573d2d52addSAlexander Pyhalov errors = 1; 574d2d52addSAlexander Pyhalov if (!sflag) /* Silent mode */ 575d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 576d2d52addSAlexander Pyhalov "%s: can't open \"%s\"\n"), 577d2d52addSAlexander Pyhalov cmdname, name); 578d2d52addSAlexander Pyhalov return; 579d2d52addSAlexander Pyhalov } 580d2d52addSAlexander Pyhalov matched |= grep(fd, name); 581d2d52addSAlexander Pyhalov (void) close(fd); 5827c478bd9Sstevel@tonic-gate 583d2d52addSAlexander Pyhalov if (ferror(stdout)) { 584d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 585d2d52addSAlexander Pyhalov "%s: error writing to stdout\n"), 586d2d52addSAlexander Pyhalov cmdname); 587d2d52addSAlexander Pyhalov (void) fflush(stdout); 588d2d52addSAlexander Pyhalov exit(2); 589d2d52addSAlexander Pyhalov } 590d2d52addSAlexander Pyhalov 591d2d52addSAlexander Pyhalov } 592d2d52addSAlexander Pyhalov 593d2d52addSAlexander Pyhalov /* 594d2d52addSAlexander Pyhalov * Add a file of strings to the pattern list. 595d2d52addSAlexander Pyhalov */ 596d2d52addSAlexander Pyhalov static void 597d2d52addSAlexander Pyhalov addfile(const char *fn) 598d2d52addSAlexander Pyhalov { 599d2d52addSAlexander Pyhalov FILE *fp; 600d2d52addSAlexander Pyhalov char *inbuf; 601d2d52addSAlexander Pyhalov char *bufp; 602d2d52addSAlexander Pyhalov size_t bufsiz, buflen, bufused; 603d2d52addSAlexander Pyhalov 604d2d52addSAlexander Pyhalov /* 605d2d52addSAlexander Pyhalov * Open the pattern file 606d2d52addSAlexander Pyhalov */ 607d2d52addSAlexander Pyhalov if ((fp = fopen(fn, "r")) == NULL) { 608d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: can't open \"%s\"\n"), 609d2d52addSAlexander Pyhalov cmdname, fn); 610d2d52addSAlexander Pyhalov exit(2); 611d2d52addSAlexander Pyhalov } 612d2d52addSAlexander Pyhalov bufsiz = BUFSIZE; 613d2d52addSAlexander Pyhalov if ((inbuf = malloc(bufsiz)) == NULL) { 614d2d52addSAlexander Pyhalov (void) fprintf(stderr, 615d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), cmdname); 616d2d52addSAlexander Pyhalov exit(2); 617d2d52addSAlexander Pyhalov } 618d2d52addSAlexander Pyhalov bufp = inbuf; 619d2d52addSAlexander Pyhalov bufused = 0; 620d2d52addSAlexander Pyhalov /* 621d2d52addSAlexander Pyhalov * Read in the file, reallocing as we need more memory 622d2d52addSAlexander Pyhalov */ 623d2d52addSAlexander Pyhalov while (fgets(bufp, bufsiz - bufused, fp) != NULL) { 624d2d52addSAlexander Pyhalov buflen = strlen(bufp); 625d2d52addSAlexander Pyhalov bufused += buflen; 626d2d52addSAlexander Pyhalov if (bufused + 1 == bufsiz && bufp[buflen - 1] != '\n') { 627d2d52addSAlexander Pyhalov /* 628d2d52addSAlexander Pyhalov * if this line does not fit to the buffer, 629d2d52addSAlexander Pyhalov * realloc larger buffer 630d2d52addSAlexander Pyhalov */ 631d2d52addSAlexander Pyhalov bufsiz += BUFSIZE; 632d2d52addSAlexander Pyhalov if ((inbuf = realloc(inbuf, bufsiz)) == NULL) { 633d2d52addSAlexander Pyhalov (void) fprintf(stderr, 634d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 635d2d52addSAlexander Pyhalov cmdname); 636d2d52addSAlexander Pyhalov exit(2); 637d2d52addSAlexander Pyhalov } 638d2d52addSAlexander Pyhalov bufp = inbuf + bufused; 639d2d52addSAlexander Pyhalov continue; 6407c478bd9Sstevel@tonic-gate } 641d2d52addSAlexander Pyhalov if (bufp[buflen - 1] == '\n') { 642d2d52addSAlexander Pyhalov bufp[--buflen] = '\0'; 6437c478bd9Sstevel@tonic-gate } 644d2d52addSAlexander Pyhalov addpattern(inbuf); 645d2d52addSAlexander Pyhalov 646d2d52addSAlexander Pyhalov bufp = inbuf; 647d2d52addSAlexander Pyhalov bufused = 0; 6487c478bd9Sstevel@tonic-gate } 649d2d52addSAlexander Pyhalov free(inbuf); 650d2d52addSAlexander Pyhalov free(prntbuf); 651d2d52addSAlexander Pyhalov free(conbuf); 652d2d52addSAlexander Pyhalov (void) fclose(fp); 653d2d52addSAlexander Pyhalov } 6547c478bd9Sstevel@tonic-gate 655d2d52addSAlexander Pyhalov /* 656d2d52addSAlexander Pyhalov * Add a string to the pattern list. 657d2d52addSAlexander Pyhalov */ 658d2d52addSAlexander Pyhalov static void 659d2d52addSAlexander Pyhalov addpattern(char *s) 660d2d52addSAlexander Pyhalov { 661d2d52addSAlexander Pyhalov PATTERN *pp; 662d2d52addSAlexander Pyhalov char *wordbuf; 663d2d52addSAlexander Pyhalov char *np; 664d2d52addSAlexander Pyhalov 665d2d52addSAlexander Pyhalov for (; ; ) { 666d2d52addSAlexander Pyhalov np = strchr(s, '\n'); 667d2d52addSAlexander Pyhalov if (np != NULL) 668d2d52addSAlexander Pyhalov *np = '\0'; 669d2d52addSAlexander Pyhalov if ((pp = malloc(sizeof (PATTERN))) == NULL) { 670d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 671d2d52addSAlexander Pyhalov "%s: out of memory\n"), 672d2d52addSAlexander Pyhalov cmdname); 673d2d52addSAlexander Pyhalov exit(2); 674d2d52addSAlexander Pyhalov } 675d2d52addSAlexander Pyhalov if (wflag) { 676d2d52addSAlexander Pyhalov /* 677d2d52addSAlexander Pyhalov * Solaris wflag support: Add '<' '>' to pattern to 678d2d52addSAlexander Pyhalov * select it as a word. Doesn't make sense with -F 679d2d52addSAlexander Pyhalov * but we're Libertarian. 680d2d52addSAlexander Pyhalov */ 681d2d52addSAlexander Pyhalov size_t slen, wordlen; 682d2d52addSAlexander Pyhalov 683d2d52addSAlexander Pyhalov slen = strlen(s); 684d2d52addSAlexander Pyhalov wordlen = slen + 5; /* '\\' '<' s '\\' '>' '\0' */ 685d2d52addSAlexander Pyhalov if ((wordbuf = malloc(wordlen)) == NULL) { 686d2d52addSAlexander Pyhalov (void) fprintf(stderr, 687d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 688d2d52addSAlexander Pyhalov cmdname); 689d2d52addSAlexander Pyhalov exit(2); 690d2d52addSAlexander Pyhalov } 691d2d52addSAlexander Pyhalov (void) strcpy(wordbuf, "\\<"); 692d2d52addSAlexander Pyhalov (void) strcpy(wordbuf + 2, s); 693d2d52addSAlexander Pyhalov (void) strcpy(wordbuf + 2 + slen, "\\>"); 694d2d52addSAlexander Pyhalov } else { 695d2d52addSAlexander Pyhalov if ((wordbuf = strdup(s)) == NULL) { 696d2d52addSAlexander Pyhalov (void) fprintf(stderr, 697d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 698d2d52addSAlexander Pyhalov cmdname); 699d2d52addSAlexander Pyhalov exit(2); 700d2d52addSAlexander Pyhalov } 701d2d52addSAlexander Pyhalov } 702d2d52addSAlexander Pyhalov pp->pattern = wordbuf; 703d2d52addSAlexander Pyhalov pp->next = patterns; 704d2d52addSAlexander Pyhalov patterns = pp; 705d2d52addSAlexander Pyhalov if (np == NULL) 706d2d52addSAlexander Pyhalov break; 707d2d52addSAlexander Pyhalov s = np + 1; 7087c478bd9Sstevel@tonic-gate } 709d2d52addSAlexander Pyhalov } 710d2d52addSAlexander Pyhalov 711d2d52addSAlexander Pyhalov /* 712d2d52addSAlexander Pyhalov * Fix patterns. 713d2d52addSAlexander Pyhalov * Must do after all arguments read, in case later -i option. 714d2d52addSAlexander Pyhalov */ 715d2d52addSAlexander Pyhalov static void 716d2d52addSAlexander Pyhalov fixpatterns(void) 717d2d52addSAlexander Pyhalov { 718d2d52addSAlexander Pyhalov PATTERN *pp; 719d2d52addSAlexander Pyhalov int rv, fix_pattern, npatterns; 7207c478bd9Sstevel@tonic-gate 721d2d52addSAlexander Pyhalov /* 722925beec7SYuri Pankov * Fix the specified pattern if -x is specified. 723d2d52addSAlexander Pyhalov */ 724d2d52addSAlexander Pyhalov fix_pattern = !Fflag && xflag; 725d2d52addSAlexander Pyhalov 726d2d52addSAlexander Pyhalov for (npatterns = 0, pp = patterns; pp != NULL; pp = pp->next) { 727d2d52addSAlexander Pyhalov npatterns++; 728d2d52addSAlexander Pyhalov if (fix_pattern) { 729d2d52addSAlexander Pyhalov char *cp, *cq; 730d2d52addSAlexander Pyhalov size_t plen, nplen; 7317c478bd9Sstevel@tonic-gate 732d2d52addSAlexander Pyhalov plen = strlen(pp->pattern); 733d2d52addSAlexander Pyhalov /* '^' pattern '$' */ 734d2d52addSAlexander Pyhalov nplen = 1 + plen + 1 + 1; 735d2d52addSAlexander Pyhalov if ((cp = malloc(nplen)) == NULL) { 736d2d52addSAlexander Pyhalov (void) fprintf(stderr, 737d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 738d2d52addSAlexander Pyhalov cmdname); 739d2d52addSAlexander Pyhalov exit(2); 740d2d52addSAlexander Pyhalov } 741d2d52addSAlexander Pyhalov cq = cp; 742d2d52addSAlexander Pyhalov *cq++ = '^'; 743d2d52addSAlexander Pyhalov cq = strcpy(cq, pp->pattern) + plen; 744d2d52addSAlexander Pyhalov *cq++ = '$'; 745d2d52addSAlexander Pyhalov *cq = '\0'; 746d2d52addSAlexander Pyhalov free(pp->pattern); 747d2d52addSAlexander Pyhalov pp->pattern = cp; 7487c478bd9Sstevel@tonic-gate } 749d2d52addSAlexander Pyhalov 750d2d52addSAlexander Pyhalov if (Fflag) { 751d2d52addSAlexander Pyhalov if (use_wchar) { 752d2d52addSAlexander Pyhalov /* 753d2d52addSAlexander Pyhalov * Fflag && mblocale && iflag 754d2d52addSAlexander Pyhalov * Fflag && mblocale && !xflag 755d2d52addSAlexander Pyhalov */ 756d2d52addSAlexander Pyhalov size_t n; 757d2d52addSAlexander Pyhalov n = strlen(pp->pattern) + 1; 758d2d52addSAlexander Pyhalov if ((pp->wpattern = 759d2d52addSAlexander Pyhalov malloc(sizeof (wchar_t) * n)) == NULL) { 760d2d52addSAlexander Pyhalov (void) fprintf(stderr, 761d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 762d2d52addSAlexander Pyhalov cmdname); 763d2d52addSAlexander Pyhalov exit(2); 764d2d52addSAlexander Pyhalov } 765d2d52addSAlexander Pyhalov if (mbstowcs(pp->wpattern, pp->pattern, n) == 766d2d52addSAlexander Pyhalov (size_t)-1) { 767d2d52addSAlexander Pyhalov (void) fprintf(stderr, 768d2d52addSAlexander Pyhalov gettext("%s: failed to convert " 769d2d52addSAlexander Pyhalov "\"%s\" to wide-characters\n"), 770d2d52addSAlexander Pyhalov cmdname, pp->pattern); 771d2d52addSAlexander Pyhalov exit(2); 772d2d52addSAlexander Pyhalov } 773d2d52addSAlexander Pyhalov if (iflag) { 774d2d52addSAlexander Pyhalov wchar_t *wp; 775d2d52addSAlexander Pyhalov for (wp = pp->wpattern; *wp != L'\0'; 776d2d52addSAlexander Pyhalov wp++) { 777d2d52addSAlexander Pyhalov *wp = towlower((wint_t)*wp); 778d2d52addSAlexander Pyhalov } 779d2d52addSAlexander Pyhalov } 780d2d52addSAlexander Pyhalov free(pp->pattern); 781d2d52addSAlexander Pyhalov } else { 782d2d52addSAlexander Pyhalov /* 783d2d52addSAlexander Pyhalov * Fflag && mblocale && !iflag 784d2d52addSAlexander Pyhalov * Fflag && !mblocale && iflag 785d2d52addSAlexander Pyhalov * Fflag && !mblocale && !iflag 786d2d52addSAlexander Pyhalov */ 787d2d52addSAlexander Pyhalov if (iflag) { 788d2d52addSAlexander Pyhalov unsigned char *cp; 789d2d52addSAlexander Pyhalov for (cp = (unsigned char *)pp->pattern; 790d2d52addSAlexander Pyhalov *cp != '\0'; cp++) { 791d2d52addSAlexander Pyhalov *cp = tolower(*cp); 792d2d52addSAlexander Pyhalov } 793d2d52addSAlexander Pyhalov } 794d2d52addSAlexander Pyhalov } 795d2d52addSAlexander Pyhalov /* 796d2d52addSAlexander Pyhalov * fgrep: No regular expressions. 797d2d52addSAlexander Pyhalov */ 798d2d52addSAlexander Pyhalov continue; 799d2d52addSAlexander Pyhalov } 800d2d52addSAlexander Pyhalov 801d2d52addSAlexander Pyhalov /* 802d2d52addSAlexander Pyhalov * For non-fgrep, compile the regular expression, 803d2d52addSAlexander Pyhalov * give an informative error message, and exit if 804d2d52addSAlexander Pyhalov * it didn't compile. 805d2d52addSAlexander Pyhalov */ 806d2d52addSAlexander Pyhalov if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) { 807d2d52addSAlexander Pyhalov (void) regerror(rv, &pp->re, errstr, sizeof (errstr)); 808d2d52addSAlexander Pyhalov (void) fprintf(stderr, 809d2d52addSAlexander Pyhalov gettext("%s: RE error in %s: %s\n"), 810d2d52addSAlexander Pyhalov cmdname, pp->pattern, errstr); 811d2d52addSAlexander Pyhalov exit(2); 812d2d52addSAlexander Pyhalov } 813d2d52addSAlexander Pyhalov free(pp->pattern); 814d2d52addSAlexander Pyhalov } 815d2d52addSAlexander Pyhalov 816d2d52addSAlexander Pyhalov /* 817d2d52addSAlexander Pyhalov * Decide if we are able to run the Boyer-Moore-Gosper algorithm. 818d2d52addSAlexander Pyhalov * Use the Boyer-Moore-Gosper algorithm if: 819d2d52addSAlexander Pyhalov * - fgrep (Fflag) 820d2d52addSAlexander Pyhalov * - singlebyte locale (!mblocale) 821d2d52addSAlexander Pyhalov * - no ignoring case (!iflag) 822d2d52addSAlexander Pyhalov * - no printing line numbers (!nflag) 823d2d52addSAlexander Pyhalov * - no negating the output (nvflag) 824d2d52addSAlexander Pyhalov * - only one pattern (npatterns == 1) 825d2d52addSAlexander Pyhalov * - non zero length pattern (strlen(patterns->pattern) != 0) 826d2d52addSAlexander Pyhalov * - no context required (conflag == 0) 827d2d52addSAlexander Pyhalov * 828d2d52addSAlexander Pyhalov * It's guaranteed patterns->pattern is still alive 829d2d52addSAlexander Pyhalov * when Fflag && !mblocale. 830d2d52addSAlexander Pyhalov */ 831d2d52addSAlexander Pyhalov use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag && 832d2d52addSAlexander Pyhalov (npatterns == 1) && (strlen(patterns->pattern) != 0) && 833d2d52addSAlexander Pyhalov conflag == 0; 834d2d52addSAlexander Pyhalov } 835d2d52addSAlexander Pyhalov 836d2d52addSAlexander Pyhalov /* 837d2d52addSAlexander Pyhalov * Search a newline from the beginning of the string 838d2d52addSAlexander Pyhalov */ 839d2d52addSAlexander Pyhalov static char * 840d2d52addSAlexander Pyhalov find_nl(const char *ptr, size_t len) 841d2d52addSAlexander Pyhalov { 842d2d52addSAlexander Pyhalov while (len-- != 0) { 843d2d52addSAlexander Pyhalov if (*ptr++ == '\n') { 844d2d52addSAlexander Pyhalov return ((char *)--ptr); 845d2d52addSAlexander Pyhalov } 846d2d52addSAlexander Pyhalov } 847d2d52addSAlexander Pyhalov return (NULL); 848d2d52addSAlexander Pyhalov } 849d2d52addSAlexander Pyhalov 850d2d52addSAlexander Pyhalov /* 851d2d52addSAlexander Pyhalov * Search a newline from the end of the string 852d2d52addSAlexander Pyhalov */ 853d2d52addSAlexander Pyhalov static char * 854d2d52addSAlexander Pyhalov rfind_nl(const char *ptr, size_t len) 855d2d52addSAlexander Pyhalov { 856d2d52addSAlexander Pyhalov const char *uptr = ptr + len; 857d2d52addSAlexander Pyhalov while (len--) { 858d2d52addSAlexander Pyhalov if (*--uptr == '\n') { 859d2d52addSAlexander Pyhalov return ((char *)uptr); 860d2d52addSAlexander Pyhalov } 861d2d52addSAlexander Pyhalov } 862d2d52addSAlexander Pyhalov return (NULL); 863d2d52addSAlexander Pyhalov } 864d2d52addSAlexander Pyhalov 865d2d52addSAlexander Pyhalov /* 866d2d52addSAlexander Pyhalov * Duplicate the specified string converting each character 867d2d52addSAlexander Pyhalov * into a lower case. 868d2d52addSAlexander Pyhalov */ 869d2d52addSAlexander Pyhalov static char * 870d2d52addSAlexander Pyhalov istrdup(const char *s1) 871d2d52addSAlexander Pyhalov { 872d2d52addSAlexander Pyhalov static size_t ibuflen = 0; 873d2d52addSAlexander Pyhalov static char *ibuf = NULL; 874d2d52addSAlexander Pyhalov size_t slen; 875d2d52addSAlexander Pyhalov char *p; 876d2d52addSAlexander Pyhalov 877d2d52addSAlexander Pyhalov slen = strlen(s1); 878d2d52addSAlexander Pyhalov if (slen >= ibuflen) { 879d2d52addSAlexander Pyhalov /* ibuf does not fit to s1 */ 880d2d52addSAlexander Pyhalov ibuflen = slen + 1; 881d2d52addSAlexander Pyhalov ibuf = realloc(ibuf, ibuflen); 882d2d52addSAlexander Pyhalov if (ibuf == NULL) { 883d2d52addSAlexander Pyhalov (void) fprintf(stderr, 884d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), cmdname); 885d2d52addSAlexander Pyhalov exit(2); 886d2d52addSAlexander Pyhalov } 887d2d52addSAlexander Pyhalov } 888d2d52addSAlexander Pyhalov p = ibuf; 889d2d52addSAlexander Pyhalov do { 890d2d52addSAlexander Pyhalov *p++ = tolower(*s1); 891d2d52addSAlexander Pyhalov } while (*s1++ != '\0'); 892d2d52addSAlexander Pyhalov return (ibuf); 893d2d52addSAlexander Pyhalov } 894d2d52addSAlexander Pyhalov 895d2d52addSAlexander Pyhalov /* 896d2d52addSAlexander Pyhalov * Do grep on a single file. 897d2d52addSAlexander Pyhalov * Return true in any lines matched. 898d2d52addSAlexander Pyhalov * 899d2d52addSAlexander Pyhalov * We have two strategies: 900d2d52addSAlexander Pyhalov * The fast one is used when we have a single pattern with 901d2d52addSAlexander Pyhalov * a string known to occur in the pattern. We can then 902d2d52addSAlexander Pyhalov * do a BMG match on the whole buffer. 903d2d52addSAlexander Pyhalov * This is an order of magnitude faster. 904d2d52addSAlexander Pyhalov * Otherwise we split the buffer into lines, 905d2d52addSAlexander Pyhalov * and check for a match on each line. 906d2d52addSAlexander Pyhalov */ 907d2d52addSAlexander Pyhalov static int 908d2d52addSAlexander Pyhalov grep(int fd, const char *fn) 909d2d52addSAlexander Pyhalov { 910d2d52addSAlexander Pyhalov PATTERN *pp; 911d2d52addSAlexander Pyhalov off_t data_len; /* length of the data chunk */ 912d2d52addSAlexander Pyhalov off_t line_len; /* length of the current line */ 913d2d52addSAlexander Pyhalov off_t line_offset; /* current line's offset from the beginning */ 914d2d52addSAlexander Pyhalov off_t blkoffset; /* line_offset but context-compatible */ 915d2d52addSAlexander Pyhalov long long lineno, linenum; 916d2d52addSAlexander Pyhalov long long matches = 0; /* Number of matching lines */ 9174adc6f15SPeter Tribble long long conacnt = 0, conbcnt = 0; /* context line count */ 918d2d52addSAlexander Pyhalov int newlinep; /* 0 if the last line of file has no newline */ 919d2d52addSAlexander Pyhalov char *ptr, *ptrend, *prntptr, *prntptrend; 920d2d52addSAlexander Pyhalov char *nextptr = NULL, *nextend = NULL; 921d2d52addSAlexander Pyhalov char *conptr = NULL, *conptrend = NULL; 922d2d52addSAlexander Pyhalov char *matchptr = NULL; 923d2d52addSAlexander Pyhalov int conaprnt = 0, conbprnt = 0, lastmatch = 0; 924d2d52addSAlexander Pyhalov boolean_t nearmatch; /* w/in N+1 of last match */ 925d2d52addSAlexander Pyhalov boolean_t havematch = B_FALSE; /* have a match in context */ 926d2d52addSAlexander Pyhalov size_t prntlen; 927d2d52addSAlexander Pyhalov 928d2d52addSAlexander Pyhalov if (patterns == NULL) 929d2d52addSAlexander Pyhalov return (0); /* no patterns to match -- just return */ 930d2d52addSAlexander Pyhalov 931d2d52addSAlexander Pyhalov pp = patterns; 932d2d52addSAlexander Pyhalov 933d2d52addSAlexander Pyhalov if (use_bmg) { 934d2d52addSAlexander Pyhalov bmgcomp(pp->pattern, strlen(pp->pattern)); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 937d2d52addSAlexander Pyhalov if (use_wchar && outline == NULL) { 938d2d52addSAlexander Pyhalov outbuflen = BUFSIZE + 1; 939d2d52addSAlexander Pyhalov outline = malloc(sizeof (wchar_t) * outbuflen); 940d2d52addSAlexander Pyhalov if (outline == NULL) { 941d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"), 942d2d52addSAlexander Pyhalov cmdname); 943d2d52addSAlexander Pyhalov exit(2); 944d2d52addSAlexander Pyhalov } 945d2d52addSAlexander Pyhalov } 946d2d52addSAlexander Pyhalov 947d2d52addSAlexander Pyhalov if (prntbuf == NULL) { 948d2d52addSAlexander Pyhalov prntbuflen = BUFSIZE; 949d2d52addSAlexander Pyhalov if ((prntbuf = malloc(prntbuflen + 1)) == NULL) { 950d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"), 951d2d52addSAlexander Pyhalov cmdname); 952d2d52addSAlexander Pyhalov exit(2); 953d2d52addSAlexander Pyhalov } 954d2d52addSAlexander Pyhalov } 955d2d52addSAlexander Pyhalov 956d2d52addSAlexander Pyhalov if (conflag != 0 && (conbuf == NULL)) { 957d2d52addSAlexander Pyhalov conbuflen = BUFSIZE; 958d2d52addSAlexander Pyhalov if ((conbuf = malloc(BUFSIZE+1)) == NULL) { 959d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"), 960d2d52addSAlexander Pyhalov cmdname); 961d2d52addSAlexander Pyhalov exit(2); 962d2d52addSAlexander Pyhalov } 963d2d52addSAlexander Pyhalov } 9647c478bd9Sstevel@tonic-gate 965d2d52addSAlexander Pyhalov nearmatch = (conmatches != 0); 966d2d52addSAlexander Pyhalov blkoffset = line_offset = 0; 967d2d52addSAlexander Pyhalov lineno = 0; 968d2d52addSAlexander Pyhalov linenum = 1; 969d2d52addSAlexander Pyhalov newlinep = 1; 970d2d52addSAlexander Pyhalov data_len = 0; 971d2d52addSAlexander Pyhalov for (; ; ) { 972d2d52addSAlexander Pyhalov long count; 973d2d52addSAlexander Pyhalov off_t offset = 0; 974d2d52addSAlexander Pyhalov char separate; 975d2d52addSAlexander Pyhalov boolean_t last_ctx = B_FALSE, eof = B_FALSE; 976d2d52addSAlexander Pyhalov 977d2d52addSAlexander Pyhalov if (data_len == 0) { 978d2d52addSAlexander Pyhalov /* 979d2d52addSAlexander Pyhalov * If no data in the buffer, reset ptr 980d2d52addSAlexander Pyhalov */ 981d2d52addSAlexander Pyhalov ptr = prntbuf; 982d2d52addSAlexander Pyhalov if (conflag != 0 && conptr == NULL) { 983d2d52addSAlexander Pyhalov conptr = conbuf; 984d2d52addSAlexander Pyhalov conptrend = conptr - 1; 985d2d52addSAlexander Pyhalov } 986d2d52addSAlexander Pyhalov } 987d2d52addSAlexander Pyhalov if (ptr == prntbuf) { 9887c478bd9Sstevel@tonic-gate /* 989d2d52addSAlexander Pyhalov * The current data chunk starts from prntbuf. 990d2d52addSAlexander Pyhalov * This means either the buffer has no data 991d2d52addSAlexander Pyhalov * or the buffer has no newline. 992d2d52addSAlexander Pyhalov * So, read more data from input. 9937c478bd9Sstevel@tonic-gate */ 994d2d52addSAlexander Pyhalov count = read(fd, ptr + data_len, prntbuflen - data_len); 995d2d52addSAlexander Pyhalov if (count < 0) { 996d2d52addSAlexander Pyhalov /* read error */ 997d2d52addSAlexander Pyhalov if (cflag) { 998d2d52addSAlexander Pyhalov if (outfn && !rflag) { 999d2d52addSAlexander Pyhalov (void) fprintf(stdout, 1000d2d52addSAlexander Pyhalov "%s:", fn); 1001d2d52addSAlexander Pyhalov } 1002d2d52addSAlexander Pyhalov if (!qflag && !rflag) { 1003d2d52addSAlexander Pyhalov (void) fprintf(stdout, "%lld\n", 1004d2d52addSAlexander Pyhalov matches); 1005d2d52addSAlexander Pyhalov } 1006d2d52addSAlexander Pyhalov } 1007d2d52addSAlexander Pyhalov return (0); 1008d2d52addSAlexander Pyhalov } else if (count == 0) { 1009d2d52addSAlexander Pyhalov /* no new data */ 1010d2d52addSAlexander Pyhalov eof = B_TRUE; 1011d2d52addSAlexander Pyhalov 1012d2d52addSAlexander Pyhalov if (data_len == 0) { 1013d2d52addSAlexander Pyhalov /* end of file already reached */ 1014d2d52addSAlexander Pyhalov if (conflag != 0) { 1015d2d52addSAlexander Pyhalov if (conptrend >= conptr) 1016d2d52addSAlexander Pyhalov *conptrend = '\n'; 1017d2d52addSAlexander Pyhalov last_ctx = B_TRUE; 1018d2d52addSAlexander Pyhalov goto L_next_line; 1019d2d52addSAlexander Pyhalov } else { 1020d2d52addSAlexander Pyhalov goto out; 1021d2d52addSAlexander Pyhalov } 1022d2d52addSAlexander Pyhalov } 1023d2d52addSAlexander Pyhalov /* last line of file has no newline */ 1024d2d52addSAlexander Pyhalov ptrend = ptr + data_len; 1025d2d52addSAlexander Pyhalov newlinep = 0; 1026d2d52addSAlexander Pyhalov goto L_start_process; 1027d2d52addSAlexander Pyhalov } 1028d2d52addSAlexander Pyhalov offset = data_len; 1029d2d52addSAlexander Pyhalov data_len += count; 1030d2d52addSAlexander Pyhalov } 1031d2d52addSAlexander Pyhalov 1032d2d52addSAlexander Pyhalov /* 1033d2d52addSAlexander Pyhalov * Look for newline in the chunk 1034d2d52addSAlexander Pyhalov * between ptr + offset and ptr + data_len - offset. 1035d2d52addSAlexander Pyhalov */ 1036d2d52addSAlexander Pyhalov ptrend = find_nl(ptr + offset, data_len - offset); 1037d2d52addSAlexander Pyhalov if (ptrend == NULL) { 1038d2d52addSAlexander Pyhalov /* no newline found in this chunk */ 10397c478bd9Sstevel@tonic-gate if (ptr > prntbuf) { 1040d2d52addSAlexander Pyhalov /* 1041d2d52addSAlexander Pyhalov * Move remaining data to the beginning 1042d2d52addSAlexander Pyhalov * of the buffer. 1043d2d52addSAlexander Pyhalov * Remaining data lie from ptr for 1044d2d52addSAlexander Pyhalov * data_len bytes. 1045d2d52addSAlexander Pyhalov */ 1046d2d52addSAlexander Pyhalov (void) memmove(prntbuf, ptr, data_len); 10477c478bd9Sstevel@tonic-gate } 1048d2d52addSAlexander Pyhalov if (data_len == prntbuflen) { 1049d2d52addSAlexander Pyhalov /* 1050d2d52addSAlexander Pyhalov * Not enough room in the buffer 1051d2d52addSAlexander Pyhalov */ 1052d2d52addSAlexander Pyhalov if (prntbuflen > SIZE_MAX - BUFSIZE) { 1053d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1054d2d52addSAlexander Pyhalov gettext("%s: buflen would" 1055d2d52addSAlexander Pyhalov " overflow\n"), 1056d2d52addSAlexander Pyhalov cmdname); 1057d2d52addSAlexander Pyhalov exit(2); 1058d2d52addSAlexander Pyhalov } 1059d2d52addSAlexander Pyhalov 1060d2d52addSAlexander Pyhalov prntbuflen += BUFSIZE; 1061d2d52addSAlexander Pyhalov prntbuf = realloc(prntbuf, prntbuflen + 1); 1062d2d52addSAlexander Pyhalov if (prntbuf == NULL) { 1063d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1064d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 1065d2d52addSAlexander Pyhalov cmdname); 1066d2d52addSAlexander Pyhalov exit(2); 1067d2d52addSAlexander Pyhalov } 1068d2d52addSAlexander Pyhalov } 1069d2d52addSAlexander Pyhalov ptr = prntbuf; 1070d2d52addSAlexander Pyhalov /* read the next input */ 1071d2d52addSAlexander Pyhalov continue; 1072d2d52addSAlexander Pyhalov } 1073d2d52addSAlexander Pyhalov L_start_process: 10747c478bd9Sstevel@tonic-gate 1075d2d52addSAlexander Pyhalov /* 1076d2d52addSAlexander Pyhalov * Beginning of the chunk: ptr 1077d2d52addSAlexander Pyhalov * End of the chunk: ptr + data_len 1078d2d52addSAlexander Pyhalov * Beginning of the line: ptr 1079d2d52addSAlexander Pyhalov * End of the line: ptrend 1080d2d52addSAlexander Pyhalov * 1081d2d52addSAlexander Pyhalov * conptr: Beginning of the context. 1082d2d52addSAlexander Pyhalov * conptrend: If context is empty, conptr - 1 (invalid memory). 1083d2d52addSAlexander Pyhalov * Otherwise, Last newline in the context. 1084d2d52addSAlexander Pyhalov */ 1085d2d52addSAlexander Pyhalov 1086d2d52addSAlexander Pyhalov if (use_bmg) { 10877c478bd9Sstevel@tonic-gate /* 1088d2d52addSAlexander Pyhalov * Use Boyer-Moore-Gosper algorithm to find out if 1089d2d52addSAlexander Pyhalov * this chunk (not this line) contains the specified 1090d2d52addSAlexander Pyhalov * pattern. If not, restart from the last line 1091d2d52addSAlexander Pyhalov * of this chunk. 10927c478bd9Sstevel@tonic-gate */ 1093d2d52addSAlexander Pyhalov char *bline; 1094d2d52addSAlexander Pyhalov bline = bmgexec(ptr, ptr + data_len); 1095d2d52addSAlexander Pyhalov if (bline == NULL) { 10967c478bd9Sstevel@tonic-gate /* 1097d2d52addSAlexander Pyhalov * No pattern found in this chunk. 1098d2d52addSAlexander Pyhalov * Need to find the last line 1099d2d52addSAlexander Pyhalov * in this chunk. 11007c478bd9Sstevel@tonic-gate */ 1101d2d52addSAlexander Pyhalov ptrend = rfind_nl(ptr, data_len); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate /* 1104d2d52addSAlexander Pyhalov * When this chunk does not contain newline, 1105d2d52addSAlexander Pyhalov * ptrend becomes NULL, which should happen 1106d2d52addSAlexander Pyhalov * when the last line of file does not end 1107d2d52addSAlexander Pyhalov * with a newline. At such a point, 1108d2d52addSAlexander Pyhalov * newlinep should have been set to 0. 1109d2d52addSAlexander Pyhalov * Therefore, just after jumping to 1110d2d52addSAlexander Pyhalov * L_skip_line, the main for-loop quits, 1111d2d52addSAlexander Pyhalov * and the line_len value won't be 1112d2d52addSAlexander Pyhalov * used. 1113d2d52addSAlexander Pyhalov */ 1114d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1115d2d52addSAlexander Pyhalov goto L_skip_line; 1116d2d52addSAlexander Pyhalov } 1117d2d52addSAlexander Pyhalov if (bline > ptrend) { 1118d2d52addSAlexander Pyhalov /* 1119d2d52addSAlexander Pyhalov * Pattern found not in the first line 1120d2d52addSAlexander Pyhalov * of this chunk. 1121d2d52addSAlexander Pyhalov * Discard the first line. 11227c478bd9Sstevel@tonic-gate */ 1123d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1124d2d52addSAlexander Pyhalov goto L_skip_line; 1125d2d52addSAlexander Pyhalov } 1126d2d52addSAlexander Pyhalov /* 1127d2d52addSAlexander Pyhalov * Pattern found in the first line of this chunk. 1128d2d52addSAlexander Pyhalov * Using this result. 1129d2d52addSAlexander Pyhalov */ 1130d2d52addSAlexander Pyhalov *ptrend = '\0'; 1131d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1132d2d52addSAlexander Pyhalov 1133d2d52addSAlexander Pyhalov /* 1134d2d52addSAlexander Pyhalov * before jumping to L_next_line, 1135d2d52addSAlexander Pyhalov * need to handle xflag if specified 1136d2d52addSAlexander Pyhalov */ 1137d2d52addSAlexander Pyhalov if (xflag && (line_len != bmglen || 1138d2d52addSAlexander Pyhalov strcmp(bmgpat, ptr) != 0)) { 1139d2d52addSAlexander Pyhalov /* didn't match */ 1140d2d52addSAlexander Pyhalov pp = NULL; 1141d2d52addSAlexander Pyhalov } else { 1142d2d52addSAlexander Pyhalov pp = patterns; /* to make it happen */ 1143d2d52addSAlexander Pyhalov } 1144d2d52addSAlexander Pyhalov goto L_next_line; 1145d2d52addSAlexander Pyhalov } 1146d2d52addSAlexander Pyhalov lineno++; 1147d2d52addSAlexander Pyhalov /* 1148d2d52addSAlexander Pyhalov * Line starts from ptr and ends at ptrend. 1149d2d52addSAlexander Pyhalov * line_len will be the length of the line. 1150d2d52addSAlexander Pyhalov */ 1151d2d52addSAlexander Pyhalov *ptrend = '\0'; 1152d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1153d2d52addSAlexander Pyhalov 1154d2d52addSAlexander Pyhalov /* 1155d2d52addSAlexander Pyhalov * From now, the process will be performed based 1156d2d52addSAlexander Pyhalov * on the line from ptr to ptrend. 1157d2d52addSAlexander Pyhalov */ 1158d2d52addSAlexander Pyhalov if (use_wchar) { 1159d2d52addSAlexander Pyhalov size_t len; 1160d2d52addSAlexander Pyhalov 1161d2d52addSAlexander Pyhalov if (line_len >= outbuflen) { 1162d2d52addSAlexander Pyhalov outbuflen = line_len + 1; 1163d2d52addSAlexander Pyhalov outline = realloc(outline, 1164d2d52addSAlexander Pyhalov sizeof (wchar_t) * outbuflen); 1165d2d52addSAlexander Pyhalov if (outline == NULL) { 1166d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1167d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 1168d2d52addSAlexander Pyhalov cmdname); 11697c478bd9Sstevel@tonic-gate exit(2); 1170d2d52addSAlexander Pyhalov } 1171d2d52addSAlexander Pyhalov } 11727c478bd9Sstevel@tonic-gate 1173d2d52addSAlexander Pyhalov len = mbstowcs(outline, ptr, line_len); 1174d2d52addSAlexander Pyhalov if (len == (size_t)-1) { 1175d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 1176d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: invalid multibyte character\n"), 1177d2d52addSAlexander Pyhalov cmdname, fn, lineno); 1178d2d52addSAlexander Pyhalov /* never match a line with invalid sequence */ 1179d2d52addSAlexander Pyhalov goto L_skip_line; 11807c478bd9Sstevel@tonic-gate } 1181d2d52addSAlexander Pyhalov outline[len] = L'\0'; 11827c478bd9Sstevel@tonic-gate 1183d2d52addSAlexander Pyhalov if (iflag) { 1184d2d52addSAlexander Pyhalov wchar_t *cp; 1185d2d52addSAlexander Pyhalov for (cp = outline; *cp != '\0'; cp++) { 1186d2d52addSAlexander Pyhalov *cp = towlower((wint_t)*cp); 1187d2d52addSAlexander Pyhalov } 1188d2d52addSAlexander Pyhalov } 11897c478bd9Sstevel@tonic-gate 1190d2d52addSAlexander Pyhalov if (xflag) { 1191d2d52addSAlexander Pyhalov for (pp = patterns; pp; pp = pp->next) { 1192d2d52addSAlexander Pyhalov if (outline[0] == pp->wpattern[0] && 1193d2d52addSAlexander Pyhalov wcscmp(outline, 1194d2d52addSAlexander Pyhalov pp->wpattern) == 0) { 1195d2d52addSAlexander Pyhalov /* matched */ 1196d2d52addSAlexander Pyhalov break; 1197d2d52addSAlexander Pyhalov } 1198d2d52addSAlexander Pyhalov } 1199d2d52addSAlexander Pyhalov } else { 1200d2d52addSAlexander Pyhalov for (pp = patterns; pp; pp = pp->next) { 1201d2d52addSAlexander Pyhalov if (wcswcs(outline, pp->wpattern) 1202d2d52addSAlexander Pyhalov != NULL) { 1203d2d52addSAlexander Pyhalov /* matched */ 1204d2d52addSAlexander Pyhalov break; 1205d2d52addSAlexander Pyhalov } 1206d2d52addSAlexander Pyhalov } 1207d2d52addSAlexander Pyhalov } 1208d2d52addSAlexander Pyhalov } else if (Fflag) { 1209d2d52addSAlexander Pyhalov /* fgrep in byte-oriented handling */ 1210d2d52addSAlexander Pyhalov char *fptr; 1211d2d52addSAlexander Pyhalov if (iflag) { 1212d2d52addSAlexander Pyhalov fptr = istrdup(ptr); 1213d2d52addSAlexander Pyhalov } else { 1214d2d52addSAlexander Pyhalov fptr = ptr; 1215d2d52addSAlexander Pyhalov } 1216d2d52addSAlexander Pyhalov if (xflag) { 1217d2d52addSAlexander Pyhalov /* fgrep -x */ 1218d2d52addSAlexander Pyhalov for (pp = patterns; pp; pp = pp->next) { 1219d2d52addSAlexander Pyhalov if (fptr[0] == pp->pattern[0] && 1220d2d52addSAlexander Pyhalov strcmp(fptr, pp->pattern) == 0) { 1221d2d52addSAlexander Pyhalov /* matched */ 1222d2d52addSAlexander Pyhalov break; 1223d2d52addSAlexander Pyhalov } 1224d2d52addSAlexander Pyhalov } 1225d2d52addSAlexander Pyhalov } else { 1226d2d52addSAlexander Pyhalov for (pp = patterns; pp; pp = pp->next) { 1227d2d52addSAlexander Pyhalov if (strstr(fptr, pp->pattern) != NULL) { 1228d2d52addSAlexander Pyhalov /* matched */ 1229d2d52addSAlexander Pyhalov break; 1230d2d52addSAlexander Pyhalov } 1231d2d52addSAlexander Pyhalov } 1232d2d52addSAlexander Pyhalov } 1233d2d52addSAlexander Pyhalov } else { 1234d2d52addSAlexander Pyhalov /* grep or egrep */ 1235d2d52addSAlexander Pyhalov for (pp = patterns; pp; pp = pp->next) { 1236d2d52addSAlexander Pyhalov int rv; 12377c478bd9Sstevel@tonic-gate 1238d2d52addSAlexander Pyhalov rv = regexec(&pp->re, ptr, 0, NULL, 0); 1239d2d52addSAlexander Pyhalov if (rv == REG_OK) { 1240d2d52addSAlexander Pyhalov /* matched */ 1241d2d52addSAlexander Pyhalov break; 1242d2d52addSAlexander Pyhalov } 1243d2d52addSAlexander Pyhalov 1244d2d52addSAlexander Pyhalov switch (rv) { 1245d2d52addSAlexander Pyhalov case REG_NOMATCH: 1246d2d52addSAlexander Pyhalov break; 1247d2d52addSAlexander Pyhalov case REG_ECHAR: 1248d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 1249d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: invalid multibyte character\n"), 1250d2d52addSAlexander Pyhalov cmdname, fn, lineno); 1251d2d52addSAlexander Pyhalov break; 1252d2d52addSAlexander Pyhalov default: 1253d2d52addSAlexander Pyhalov (void) regerror(rv, &pp->re, errstr, 1254d2d52addSAlexander Pyhalov sizeof (errstr)); 1255d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext( 1256d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: %s\n"), 1257d2d52addSAlexander Pyhalov cmdname, fn, lineno, errstr); 1258d2d52addSAlexander Pyhalov exit(2); 1259d2d52addSAlexander Pyhalov } 1260d2d52addSAlexander Pyhalov } 1261d2d52addSAlexander Pyhalov } 1262d2d52addSAlexander Pyhalov 1263d2d52addSAlexander Pyhalov /* 1264d2d52addSAlexander Pyhalov * Context is set up as follows: 1265d2d52addSAlexander Pyhalov * For a 'Before' context, we maintain a set of pointers 1266d2d52addSAlexander Pyhalov * containing 'N' lines of context. If the current number of 1267d2d52addSAlexander Pyhalov * lines contained is greater than N, and N isn't a match, the 1268d2d52addSAlexander Pyhalov * start pointer is moved forward to the next newline. 1269d2d52addSAlexander Pyhalov * 1270d2d52addSAlexander Pyhalov * If we ever find a match, we print out immediately. 1271d2d52addSAlexander Pyhalov * 'nearmatch' tells us if we're within N+1 lines of the last 1272d2d52addSAlexander Pyhalov * match ; if we are, and we find another match, we don't 1273d2d52addSAlexander Pyhalov * separate the matches. 'nearmatch' becomes false when 1274d2d52addSAlexander Pyhalov * a line gets rotated out of the context. 1275d2d52addSAlexander Pyhalov * 1276d2d52addSAlexander Pyhalov * For an 'After' context, we simply wait until we've found a 1277d2d52addSAlexander Pyhalov * match, then create a context N+1 lines big. If we don't find 1278d2d52addSAlexander Pyhalov * a match within the context, we print out the current context. 1279d2d52addSAlexander Pyhalov * Otherwise, we save a reference to the new matching line, 1280d2d52addSAlexander Pyhalov * print out the other context, and reset our context pointers 1281d2d52addSAlexander Pyhalov * to the new matching line. 1282d2d52addSAlexander Pyhalov * 1283d2d52addSAlexander Pyhalov * 'nearmatch' becomes false when we find a non-matching line 1284d2d52addSAlexander Pyhalov * that isn't a part of any context. 1285d2d52addSAlexander Pyhalov * 1286d2d52addSAlexander Pyhalov * A full-context is implemented as a combination of the 1287d2d52addSAlexander Pyhalov * 'Before' and 'After' context logic. Before we find a match, 1288d2d52addSAlexander Pyhalov * we follow the Before logic. When we find a match, we 1289d2d52addSAlexander Pyhalov * follow the After logic. 'nearmatch' is handled by the Before 1290d2d52addSAlexander Pyhalov * logic. 1291d2d52addSAlexander Pyhalov */ 1292d2d52addSAlexander Pyhalov 1293d2d52addSAlexander Pyhalov if (conflag == 0) 1294d2d52addSAlexander Pyhalov goto L_next_line; 1295d2d52addSAlexander Pyhalov 1296d2d52addSAlexander Pyhalov /* Do we have room to add this line to the context buffer? */ 1297d9241f99SAndrew Stormont while ((line_len + 1) > (conbuflen - 1298d9241f99SAndrew Stormont ((conptrend >= conptr) ? conptrend - conbuf : 0))) { 1299d2d52addSAlexander Pyhalov char *oldconbuf = conbuf; 1300d2d52addSAlexander Pyhalov char *oldconptr = conptr; 1301d2d52addSAlexander Pyhalov long tmp = matchptr - conptr; 1302d2d52addSAlexander Pyhalov 1303d2d52addSAlexander Pyhalov if (conbuflen > SIZE_MAX - BUFSIZE) { 1304d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1305d2d52addSAlexander Pyhalov gettext("%s: buflen would overflow\n"), 1306d2d52addSAlexander Pyhalov cmdname); 1307d2d52addSAlexander Pyhalov exit(2); 1308d2d52addSAlexander Pyhalov } 1309d2d52addSAlexander Pyhalov 1310d2d52addSAlexander Pyhalov conbuflen += BUFSIZE; 1311d2d52addSAlexander Pyhalov conbuf = realloc(conbuf, conbuflen + 1); 1312d2d52addSAlexander Pyhalov if (conbuf == NULL) { 1313d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1314d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 1315d2d52addSAlexander Pyhalov cmdname); 1316d2d52addSAlexander Pyhalov exit(2); 1317d2d52addSAlexander Pyhalov } 1318d2d52addSAlexander Pyhalov 1319d2d52addSAlexander Pyhalov conptr = conbuf + (conptr - oldconbuf); 1320d2d52addSAlexander Pyhalov conptrend = conptr + (conptrend - oldconptr); 1321d2d52addSAlexander Pyhalov if (matchptr) 1322d2d52addSAlexander Pyhalov matchptr = conptr + tmp; 1323d2d52addSAlexander Pyhalov } 1324d2d52addSAlexander Pyhalov (void) memcpy(conptrend + 1, ptr, line_len); 1325d2d52addSAlexander Pyhalov conptrend += line_len + 1; 1326d2d52addSAlexander Pyhalov *conptrend = '\n'; 1327d2d52addSAlexander Pyhalov 1328d2d52addSAlexander Pyhalov if (nvflag == (pp != NULL)) { 1329d2d52addSAlexander Pyhalov /* matched */ 1330d2d52addSAlexander Pyhalov if (havematch) { 1331d2d52addSAlexander Pyhalov if ((conflag & AFTER) != 0) { 1332d2d52addSAlexander Pyhalov conaprnt = 1; 1333d2d52addSAlexander Pyhalov nextend = conptrend; 1334d2d52addSAlexander Pyhalov conptrend = conptr + lastmatch; 1335d2d52addSAlexander Pyhalov nextptr = conptrend + 1; 1336d2d52addSAlexander Pyhalov *nextend = '\n'; 1337d2d52addSAlexander Pyhalov } 1338d2d52addSAlexander Pyhalov } else { 1339d2d52addSAlexander Pyhalov if (conflag == AFTER) { 1340d2d52addSAlexander Pyhalov conptr = conptrend - (line_len); 1341d2d52addSAlexander Pyhalov linenum = lineno; 1342d2d52addSAlexander Pyhalov } 1343d2d52addSAlexander Pyhalov blkoffset = line_offset - 1344d2d52addSAlexander Pyhalov (conptrend - conptr - line_len); 1345d2d52addSAlexander Pyhalov } 1346d2d52addSAlexander Pyhalov 1347d2d52addSAlexander Pyhalov if (conflag == BEFORE) 1348d2d52addSAlexander Pyhalov conbprnt = 1; 1349d2d52addSAlexander Pyhalov 1350d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr; 1351d2d52addSAlexander Pyhalov havematch = B_TRUE; 1352d2d52addSAlexander Pyhalov goto L_next_line; 1353d2d52addSAlexander Pyhalov } 1354d2d52addSAlexander Pyhalov 1355d2d52addSAlexander Pyhalov if (!havematch) { 1356d2d52addSAlexander Pyhalov if ((conflag & BEFORE) != 0) { 1357d2d52addSAlexander Pyhalov if (conbcnt >= conblen) { 1358d2d52addSAlexander Pyhalov char *tmp = conptr; 1359d2d52addSAlexander Pyhalov conptr = find_nl(conptr, 1360d2d52addSAlexander Pyhalov conptrend - conptr) + 1; 1361d2d52addSAlexander Pyhalov if (bflag) 1362d2d52addSAlexander Pyhalov blkoffset += conptr - tmp; 1363d2d52addSAlexander Pyhalov linenum++; 1364d2d52addSAlexander Pyhalov nearmatch = B_TRUE; 1365d2d52addSAlexander Pyhalov } else { 1366d2d52addSAlexander Pyhalov conbcnt++; 1367d2d52addSAlexander Pyhalov } 1368d2d52addSAlexander Pyhalov } 1369d2d52addSAlexander Pyhalov if (conflag == AFTER) 1370d2d52addSAlexander Pyhalov nearmatch = B_TRUE; 1371d2d52addSAlexander Pyhalov } else { 1372d2d52addSAlexander Pyhalov if (++conacnt >= conalen && !conaprnt && conalen) 1373d2d52addSAlexander Pyhalov conaprnt = 1; 1374d2d52addSAlexander Pyhalov else 1375d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr; 1376d2d52addSAlexander Pyhalov } 1377d2d52addSAlexander Pyhalov 1378d2d52addSAlexander Pyhalov L_next_line: 1379d2d52addSAlexander Pyhalov /* 1380d2d52addSAlexander Pyhalov * Here, if pp points to non-NULL, something has been matched 1381d2d52addSAlexander Pyhalov * to the pattern. 1382d2d52addSAlexander Pyhalov */ 1383d2d52addSAlexander Pyhalov if (!last_ctx && nvflag == (pp != NULL)) { 1384d2d52addSAlexander Pyhalov matches++; 1385d2d52addSAlexander Pyhalov if (!nextend) 1386d2d52addSAlexander Pyhalov matchptr = (conflag != 0) ? conptrend : ptrend; 1387d2d52addSAlexander Pyhalov } 1388d2d52addSAlexander Pyhalov 1389d2d52addSAlexander Pyhalov /* 1390d2d52addSAlexander Pyhalov * Set up some print context so that we can treat 1391d2d52addSAlexander Pyhalov * single-line matches as a zero-N context. 1392d2d52addSAlexander Pyhalov * Apply CLI flags to each line of the context. 1393d2d52addSAlexander Pyhalov * 1394d2d52addSAlexander Pyhalov * For context, we only print if we both have a match and are 1395d2d52addSAlexander Pyhalov * either at the end of the data stream, or we've previously 1396d2d52addSAlexander Pyhalov * declared that we want to print for a particular context. 1397d2d52addSAlexander Pyhalov */ 1398d2d52addSAlexander Pyhalov if (havematch && (eof || conaprnt || conbprnt)) { 1399d2d52addSAlexander Pyhalov 1400d2d52addSAlexander Pyhalov /* 1401d2d52addSAlexander Pyhalov * We'd normally do this earlier, but we had to 1402d2d52addSAlexander Pyhalov * escape early because we reached the end of the data. 1403d2d52addSAlexander Pyhalov */ 1404d2d52addSAlexander Pyhalov if (eof && nextptr) 1405d2d52addSAlexander Pyhalov conptrend = nextend; 1406d2d52addSAlexander Pyhalov 1407d2d52addSAlexander Pyhalov prntlen = conptrend - conptr + 1; 1408d2d52addSAlexander Pyhalov prntptr = conptr; 1409d2d52addSAlexander Pyhalov if (conmatches++ && nearmatch && !cflag) 1410d2d52addSAlexander Pyhalov (void) fwrite("--\n", 1, 3, stdout); 1411d2d52addSAlexander Pyhalov } else if (conflag == 0 && nvflag == (pp != NULL)) { 1412d2d52addSAlexander Pyhalov *ptrend = '\n'; 1413d2d52addSAlexander Pyhalov prntlen = line_len + 1; 1414d2d52addSAlexander Pyhalov prntptr = ptr; 1415d2d52addSAlexander Pyhalov linenum = lineno; 1416d2d52addSAlexander Pyhalov blkoffset = line_offset; 1417d2d52addSAlexander Pyhalov } else if (eof) { 1418d2d52addSAlexander Pyhalov /* No match and no more data */ 1419d2d52addSAlexander Pyhalov goto out; 14207c478bd9Sstevel@tonic-gate } else { 1421d2d52addSAlexander Pyhalov /* No match, or we're not done building context */ 1422d2d52addSAlexander Pyhalov goto L_skip_line; 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 1425d2d52addSAlexander Pyhalov prntptrend = prntptr - 1; 1426d2d52addSAlexander Pyhalov while ((prntptrend = find_nl(prntptrend + 1, 1427d2d52addSAlexander Pyhalov prntlen)) != NULL) { 1428d2d52addSAlexander Pyhalov 14297c478bd9Sstevel@tonic-gate /* 1430d2d52addSAlexander Pyhalov * GNU grep uses '-' for context lines and ':' for 1431d2d52addSAlexander Pyhalov * matching lines, so replicate that here. 14327c478bd9Sstevel@tonic-gate */ 1433d2d52addSAlexander Pyhalov if (prntptrend == matchptr) { 1434d2d52addSAlexander Pyhalov if (eof && nextptr) { 1435d2d52addSAlexander Pyhalov matchptr = nextend; 1436d2d52addSAlexander Pyhalov nextptr = NULL; 1437d2d52addSAlexander Pyhalov } else { 1438d2d52addSAlexander Pyhalov matchptr = NULL; 1439d2d52addSAlexander Pyhalov } 1440d2d52addSAlexander Pyhalov separate = ':'; 1441d2d52addSAlexander Pyhalov } else { 1442d2d52addSAlexander Pyhalov separate = '-'; 1443d2d52addSAlexander Pyhalov } 1444d2d52addSAlexander Pyhalov 14457c478bd9Sstevel@tonic-gate /* 1446d2d52addSAlexander Pyhalov * Handle q, l, and c flags. 14477c478bd9Sstevel@tonic-gate */ 1448d2d52addSAlexander Pyhalov if (qflag) { 1449d2d52addSAlexander Pyhalov /* no need to continue */ 1450d2d52addSAlexander Pyhalov /* 1451d2d52addSAlexander Pyhalov * End of this line is ptrend. 1452d2d52addSAlexander Pyhalov * We have read up to ptr + data_len. 1453d2d52addSAlexander Pyhalov */ 1454d2d52addSAlexander Pyhalov off_t pos; 1455d2d52addSAlexander Pyhalov pos = ptr + data_len - (ptrend + 1); 1456d2d52addSAlexander Pyhalov (void) lseek(fd, -pos, SEEK_CUR); 1457d2d52addSAlexander Pyhalov exit(0); 1458d2d52addSAlexander Pyhalov } 1459d2d52addSAlexander Pyhalov if (lflag) { 1460d2d52addSAlexander Pyhalov (void) printf("%s\n", fn); 1461d2d52addSAlexander Pyhalov goto out; 1462d2d52addSAlexander Pyhalov } 1463*2e5ac464SRobert Mustacchi if (Lflag) { 1464*2e5ac464SRobert Mustacchi goto out; 1465*2e5ac464SRobert Mustacchi } 1466d2d52addSAlexander Pyhalov if (!cflag) { 1467d2d52addSAlexander Pyhalov if (Hflag || outfn) { 1468d2d52addSAlexander Pyhalov (void) printf("%s%c", fn, separate); 1469d2d52addSAlexander Pyhalov } 1470d2d52addSAlexander Pyhalov if (bflag) { 1471d2d52addSAlexander Pyhalov (void) printf("%lld%c", (offset_t) 1472d2d52addSAlexander Pyhalov (blkoffset / BSIZE), separate); 1473d2d52addSAlexander Pyhalov } 1474d2d52addSAlexander Pyhalov if (nflag) { 1475d2d52addSAlexander Pyhalov (void) printf("%lld%c", linenum, 1476d2d52addSAlexander Pyhalov separate); 1477d2d52addSAlexander Pyhalov } 1478d2d52addSAlexander Pyhalov (void) fwrite(prntptr, 1, 1479d2d52addSAlexander Pyhalov prntptrend - prntptr + 1, stdout); 1480d2d52addSAlexander Pyhalov } 1481d2d52addSAlexander Pyhalov if (ferror(stdout)) { 1482d2d52addSAlexander Pyhalov return (0); 1483d2d52addSAlexander Pyhalov } 1484d2d52addSAlexander Pyhalov linenum++; 1485d2d52addSAlexander Pyhalov prntlen -= prntptrend - prntptr + 1; 1486d2d52addSAlexander Pyhalov blkoffset += prntptrend - prntptr + 1; 1487d2d52addSAlexander Pyhalov prntptr = prntptrend + 1; 1488d2d52addSAlexander Pyhalov } 14897c478bd9Sstevel@tonic-gate 1490d2d52addSAlexander Pyhalov if (eof) 1491d2d52addSAlexander Pyhalov goto out; 1492d2d52addSAlexander Pyhalov 1493d2d52addSAlexander Pyhalov /* 1494d2d52addSAlexander Pyhalov * Update context buffer and variables post-print 1495d2d52addSAlexander Pyhalov */ 1496d2d52addSAlexander Pyhalov if (conflag != 0) { 1497d2d52addSAlexander Pyhalov conptr = conbuf; 1498d2d52addSAlexander Pyhalov conaprnt = conbprnt = 0; 1499d2d52addSAlexander Pyhalov nearmatch = B_FALSE; 1500d2d52addSAlexander Pyhalov conacnt = conbcnt = 0; 1501d2d52addSAlexander Pyhalov 1502d2d52addSAlexander Pyhalov if (nextptr) { 1503d2d52addSAlexander Pyhalov (void) memmove(conbuf, nextptr, 1504d2d52addSAlexander Pyhalov nextend - nextptr + 1); 1505d2d52addSAlexander Pyhalov blkoffset += nextptr - conptrend - 1; 1506d2d52addSAlexander Pyhalov conptrend = conptr + (nextend - nextptr); 1507d2d52addSAlexander Pyhalov matchptr = conptrend; 1508d2d52addSAlexander Pyhalov linenum = lineno; 1509d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr; 1510d2d52addSAlexander Pyhalov havematch = B_TRUE; 1511d2d52addSAlexander Pyhalov } else { 1512d2d52addSAlexander Pyhalov conptrend = conptr - 1; 1513d2d52addSAlexander Pyhalov conacnt = 0; 1514d2d52addSAlexander Pyhalov lastmatch = 0; 1515d2d52addSAlexander Pyhalov havematch = B_FALSE; 1516d2d52addSAlexander Pyhalov } 1517d2d52addSAlexander Pyhalov nextptr = nextend = NULL; 1518d2d52addSAlexander Pyhalov } 15197c478bd9Sstevel@tonic-gate 1520d2d52addSAlexander Pyhalov L_skip_line: 1521d2d52addSAlexander Pyhalov if (!newlinep) 15227c478bd9Sstevel@tonic-gate break; 15237c478bd9Sstevel@tonic-gate 1524d2d52addSAlexander Pyhalov data_len -= line_len + 1; 1525d2d52addSAlexander Pyhalov line_offset += line_len + 1; 1526d2d52addSAlexander Pyhalov ptr = ptrend + 1; 15277c478bd9Sstevel@tonic-gate } 15287c478bd9Sstevel@tonic-gate 1529d2d52addSAlexander Pyhalov out: 1530d2d52addSAlexander Pyhalov if (cflag) { 1531d2d52addSAlexander Pyhalov if (Hflag || outfn) { 1532d2d52addSAlexander Pyhalov (void) printf("%s:", fn); 1533d2d52addSAlexander Pyhalov } 1534d2d52addSAlexander Pyhalov if (!qflag) { 1535d2d52addSAlexander Pyhalov (void) printf("%lld\n", matches); 1536d2d52addSAlexander Pyhalov } 15377c478bd9Sstevel@tonic-gate } 1538*2e5ac464SRobert Mustacchi 1539*2e5ac464SRobert Mustacchi /* 1540*2e5ac464SRobert Mustacchi * -L tells us to print the filename only when it doesn't match. So we 1541*2e5ac464SRobert Mustacchi * run through the normal operationa and then invert it. 1542*2e5ac464SRobert Mustacchi */ 1543*2e5ac464SRobert Mustacchi if (Lflag) { 1544*2e5ac464SRobert Mustacchi if (matches == 0) { 1545*2e5ac464SRobert Mustacchi (void) printf("%s\n", fn); 1546*2e5ac464SRobert Mustacchi matches = 1; 1547*2e5ac464SRobert Mustacchi } else { 1548*2e5ac464SRobert Mustacchi matches = 0; 1549*2e5ac464SRobert Mustacchi } 1550*2e5ac464SRobert Mustacchi } 1551*2e5ac464SRobert Mustacchi 1552d2d52addSAlexander Pyhalov return (matches != 0); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 1555d2d52addSAlexander Pyhalov /* 1556d2d52addSAlexander Pyhalov * usage message for grep 1557d2d52addSAlexander Pyhalov */ 1558d2d52addSAlexander Pyhalov static void 1559d2d52addSAlexander Pyhalov usage(void) 15607c478bd9Sstevel@tonic-gate { 1561e54e6a39SYuri Pankov (void) fprintf(stderr, gettext("usage: %5s"), cmdname); 1562e54e6a39SYuri Pankov if (!egrep && !fgrep) 1563e54e6a39SYuri Pankov (void) fprintf(stderr, gettext(" [-E|-F]")); 1564*2e5ac464SRobert Mustacchi (void) fprintf(stderr, gettext(" [-bchHilLnqrRsvx] [-A num] [-B num] " 1565e54e6a39SYuri Pankov "[-C num|-num]\n [-e pattern_list]... " 1566e54e6a39SYuri Pankov "[-f pattern_file]... [pattern_list] [file]...\n")); 1567d2d52addSAlexander Pyhalov exit(2); 1568d2d52addSAlexander Pyhalov /* NOTREACHED */ 1569d2d52addSAlexander Pyhalov } 15707c478bd9Sstevel@tonic-gate 1571d2d52addSAlexander Pyhalov /* 1572d2d52addSAlexander Pyhalov * Compile literal pattern into BMG tables 1573d2d52addSAlexander Pyhalov */ 1574d2d52addSAlexander Pyhalov static void 1575d2d52addSAlexander Pyhalov bmgcomp(char *pat, int len) 1576d2d52addSAlexander Pyhalov { 1577d2d52addSAlexander Pyhalov int i; 1578d2d52addSAlexander Pyhalov int tlen; 1579d2d52addSAlexander Pyhalov unsigned char *uc = (unsigned char *)pat; 15807c478bd9Sstevel@tonic-gate 1581d2d52addSAlexander Pyhalov bmglen = len; 1582d2d52addSAlexander Pyhalov bmgpat = pat; 15837c478bd9Sstevel@tonic-gate 1584d2d52addSAlexander Pyhalov for (i = 0; i < M_CSETSIZE; i++) { 1585d2d52addSAlexander Pyhalov bmgtab[i] = len; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 1588d2d52addSAlexander Pyhalov len--; 1589d2d52addSAlexander Pyhalov for (tlen = len, i = 0; i <= len; i++, tlen--) { 1590d2d52addSAlexander Pyhalov bmgtab[*uc++] = tlen; 1591d2d52addSAlexander Pyhalov } 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate 1594d2d52addSAlexander Pyhalov /* 1595d2d52addSAlexander Pyhalov * BMG search. 1596d2d52addSAlexander Pyhalov */ 1597d2d52addSAlexander Pyhalov static char * 1598d2d52addSAlexander Pyhalov bmgexec(char *str, char *end) 15997c478bd9Sstevel@tonic-gate { 1600d2d52addSAlexander Pyhalov int t; 1601d2d52addSAlexander Pyhalov char *k, *s, *p; 16027c478bd9Sstevel@tonic-gate 1603d2d52addSAlexander Pyhalov k = str + bmglen - 1; 1604d2d52addSAlexander Pyhalov if (bmglen == 1) { 1605d2d52addSAlexander Pyhalov return (memchr(str, bmgpat[0], end - str)); 1606d2d52addSAlexander Pyhalov } 1607d2d52addSAlexander Pyhalov for (; ; ) { 1608d2d52addSAlexander Pyhalov /* inner loop, should be most optimized */ 1609d2d52addSAlexander Pyhalov while (k < end && (t = bmgtab[(unsigned char)*k]) != 0) { 1610d2d52addSAlexander Pyhalov k += t; 1611d2d52addSAlexander Pyhalov } 1612d2d52addSAlexander Pyhalov if (k >= end) { 1613d2d52addSAlexander Pyhalov return (NULL); 1614d2d52addSAlexander Pyhalov } 1615d2d52addSAlexander Pyhalov for (s = k, p = bmgpat + bmglen - 1; *--s == *--p; ) { 1616d2d52addSAlexander Pyhalov if (p == bmgpat) { 1617d2d52addSAlexander Pyhalov return (s); 1618d2d52addSAlexander Pyhalov } 1619d2d52addSAlexander Pyhalov } 1620d2d52addSAlexander Pyhalov k++; 1621d2d52addSAlexander Pyhalov } 1622d2d52addSAlexander Pyhalov /* NOTREACHED */ 16237c478bd9Sstevel@tonic-gate } 1624