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 */ 111*81dd18d8SRobert 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 115*81dd18d8SRobert Mustacchi static int use_bmg, mblocale; 116d2d52addSAlexander Pyhalov 117*81dd18d8SRobert 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++; 186*81dd18d8SRobert 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 222*81dd18d8SRobert 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++; 325*81dd18d8SRobert 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 388*81dd18d8SRobert Mustacchi case 'o': 389*81dd18d8SRobert Mustacchi oflag++; 390*81dd18d8SRobert Mustacchi break; 391*81dd18d8SRobert 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 /* 439*81dd18d8SRobert Mustacchi * -l or -L overrides -H like in GNU grep. It also overrides -o. 440d2d52addSAlexander Pyhalov */ 441*81dd18d8SRobert Mustacchi if (lflag || Lflag) { 442d2d52addSAlexander Pyhalov Hflag = 0; 443*81dd18d8SRobert Mustacchi oflag = 0; 444*81dd18d8SRobert 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. 450*81dd18d8SRobert Mustacchi * -c overrides -o in GNU grep, we honor that. 451d2d52addSAlexander Pyhalov */ 452*81dd18d8SRobert Mustacchi if (cflag) { 453d2d52addSAlexander Pyhalov lflag = 0; 4542e5ac464SRobert Mustacchi Lflag = 0; 455*81dd18d8SRobert Mustacchi oflag = 0; 456*81dd18d8SRobert Mustacchi } 457*81dd18d8SRobert Mustacchi 458*81dd18d8SRobert Mustacchi /* 459*81dd18d8SRobert Mustacchi * If -o is set then we ignore all context related options, like other 460*81dd18d8SRobert Mustacchi * greps. 461*81dd18d8SRobert Mustacchi */ 462*81dd18d8SRobert Mustacchi if (oflag) { 463*81dd18d8SRobert Mustacchi conflag = 0; 464*81dd18d8SRobert Mustacchi } 465*81dd18d8SRobert Mustacchi 466*81dd18d8SRobert Mustacchi /* 467*81dd18d8SRobert Mustacchi * These flags are a semantic mess with no clear answers as to their 468*81dd18d8SRobert Mustacchi * behvaior. Based on some experimentation GNU grep will exit zero if a 469*81dd18d8SRobert Mustacchi * non-match is present, but never print anything. BSD grep seems to 470*81dd18d8SRobert Mustacchi * exit 1 and not print anything, even if there would have been a match. 471*81dd18d8SRobert Mustacchi * Also, you probably don't want to ask about what happens with grep -x 472*81dd18d8SRobert Mustacchi * -o -v, some implementations seem to just ignore -v. 473*81dd18d8SRobert Mustacchi */ 474*81dd18d8SRobert Mustacchi if (oflag && !nvflag) { 475*81dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext("%s: the combination of -v and " 476*81dd18d8SRobert Mustacchi "-o is not supported currently\n"), argv[0]); 477*81dd18d8SRobert 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 758d2d52addSAlexander Pyhalov /* 759d2d52addSAlexander Pyhalov * Fix patterns. 760d2d52addSAlexander Pyhalov * Must do after all arguments read, in case later -i option. 761d2d52addSAlexander Pyhalov */ 762d2d52addSAlexander Pyhalov static void 763d2d52addSAlexander Pyhalov fixpatterns(void) 764d2d52addSAlexander Pyhalov { 765d2d52addSAlexander Pyhalov PATTERN *pp; 766*81dd18d8SRobert Mustacchi int rv, fix_pattern; 767*81dd18d8SRobert Mustacchi 768*81dd18d8SRobert Mustacchi /* 769*81dd18d8SRobert Mustacchi * Decide if we are able to run the Boyer-Moore-Gosper algorithm. 770*81dd18d8SRobert Mustacchi * Use the Boyer-Moore-Gosper algorithm if: 771*81dd18d8SRobert Mustacchi * - fgrep (Fflag) 772*81dd18d8SRobert Mustacchi * - singlebyte locale (!mblocale) 773*81dd18d8SRobert Mustacchi * - no ignoring case (!iflag) 774*81dd18d8SRobert Mustacchi * - no printing line numbers (!nflag) 775*81dd18d8SRobert Mustacchi * - no negating the output (nvflag) 776*81dd18d8SRobert Mustacchi * - only one pattern (patterns != NULL && patterns->next == 777*81dd18d8SRobert Mustacchi * NULL) 778*81dd18d8SRobert Mustacchi * - non zero length pattern (strlen(patterns->pattern) != 0) 779*81dd18d8SRobert Mustacchi * - no context required (conflag == 0) 780*81dd18d8SRobert Mustacchi * - no exact matches (!oflag) 781*81dd18d8SRobert Mustacchi */ 782*81dd18d8SRobert Mustacchi use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag && !oflag && 783*81dd18d8SRobert Mustacchi (patterns != NULL && patterns->next == NULL) && 784*81dd18d8SRobert Mustacchi (strlen(patterns->pattern) != 0) && conflag == 0; 785*81dd18d8SRobert Mustacchi 786*81dd18d8SRobert Mustacchi if (use_bmg) { 787*81dd18d8SRobert Mustacchi return; 788*81dd18d8SRobert Mustacchi } 7897c478bd9Sstevel@tonic-gate 790d2d52addSAlexander Pyhalov /* 791925beec7SYuri Pankov * Fix the specified pattern if -x is specified. 792d2d52addSAlexander Pyhalov */ 793d2d52addSAlexander Pyhalov fix_pattern = !Fflag && xflag; 794d2d52addSAlexander Pyhalov 795*81dd18d8SRobert Mustacchi for (pp = patterns; pp != NULL; pp = pp->next) { 796d2d52addSAlexander Pyhalov if (fix_pattern) { 797d2d52addSAlexander Pyhalov char *cp, *cq; 798d2d52addSAlexander Pyhalov size_t plen, nplen; 7997c478bd9Sstevel@tonic-gate 800d2d52addSAlexander Pyhalov plen = strlen(pp->pattern); 801d2d52addSAlexander Pyhalov /* '^' pattern '$' */ 802d2d52addSAlexander Pyhalov nplen = 1 + plen + 1 + 1; 803d2d52addSAlexander Pyhalov if ((cp = malloc(nplen)) == NULL) { 804d2d52addSAlexander Pyhalov (void) fprintf(stderr, 805d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 806d2d52addSAlexander Pyhalov cmdname); 807d2d52addSAlexander Pyhalov exit(2); 808d2d52addSAlexander Pyhalov } 809d2d52addSAlexander Pyhalov cq = cp; 810d2d52addSAlexander Pyhalov *cq++ = '^'; 811d2d52addSAlexander Pyhalov cq = strcpy(cq, pp->pattern) + plen; 812d2d52addSAlexander Pyhalov *cq++ = '$'; 813d2d52addSAlexander Pyhalov *cq = '\0'; 814d2d52addSAlexander Pyhalov free(pp->pattern); 815d2d52addSAlexander Pyhalov pp->pattern = cp; 8167c478bd9Sstevel@tonic-gate } 817d2d52addSAlexander Pyhalov 818d2d52addSAlexander Pyhalov /* 819*81dd18d8SRobert Mustacchi * Compile the regular expression, give an informative error 820*81dd18d8SRobert Mustacchi * message, and exit if it didn't compile. 821d2d52addSAlexander Pyhalov */ 822d2d52addSAlexander Pyhalov if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) { 823d2d52addSAlexander Pyhalov (void) regerror(rv, &pp->re, errstr, sizeof (errstr)); 824d2d52addSAlexander Pyhalov (void) fprintf(stderr, 825d2d52addSAlexander Pyhalov gettext("%s: RE error in %s: %s\n"), 826d2d52addSAlexander Pyhalov cmdname, pp->pattern, errstr); 827d2d52addSAlexander Pyhalov exit(2); 828d2d52addSAlexander Pyhalov } 829d2d52addSAlexander Pyhalov free(pp->pattern); 830d2d52addSAlexander Pyhalov } 831d2d52addSAlexander Pyhalov } 832d2d52addSAlexander Pyhalov 833d2d52addSAlexander Pyhalov /* 834d2d52addSAlexander Pyhalov * Search a newline from the beginning of the string 835d2d52addSAlexander Pyhalov */ 836d2d52addSAlexander Pyhalov static char * 837d2d52addSAlexander Pyhalov find_nl(const char *ptr, size_t len) 838d2d52addSAlexander Pyhalov { 839d2d52addSAlexander Pyhalov while (len-- != 0) { 840d2d52addSAlexander Pyhalov if (*ptr++ == '\n') { 841d2d52addSAlexander Pyhalov return ((char *)--ptr); 842d2d52addSAlexander Pyhalov } 843d2d52addSAlexander Pyhalov } 844d2d52addSAlexander Pyhalov return (NULL); 845d2d52addSAlexander Pyhalov } 846d2d52addSAlexander Pyhalov 847d2d52addSAlexander Pyhalov /* 848d2d52addSAlexander Pyhalov * Search a newline from the end of the string 849d2d52addSAlexander Pyhalov */ 850d2d52addSAlexander Pyhalov static char * 851d2d52addSAlexander Pyhalov rfind_nl(const char *ptr, size_t len) 852d2d52addSAlexander Pyhalov { 853d2d52addSAlexander Pyhalov const char *uptr = ptr + len; 854d2d52addSAlexander Pyhalov while (len--) { 855d2d52addSAlexander Pyhalov if (*--uptr == '\n') { 856d2d52addSAlexander Pyhalov return ((char *)uptr); 857d2d52addSAlexander Pyhalov } 858d2d52addSAlexander Pyhalov } 859d2d52addSAlexander Pyhalov return (NULL); 860d2d52addSAlexander Pyhalov } 861d2d52addSAlexander Pyhalov 862d2d52addSAlexander Pyhalov /* 863d2d52addSAlexander Pyhalov * Do grep on a single file. 864d2d52addSAlexander Pyhalov * Return true in any lines matched. 865d2d52addSAlexander Pyhalov * 866d2d52addSAlexander Pyhalov * We have two strategies: 867d2d52addSAlexander Pyhalov * The fast one is used when we have a single pattern with 868d2d52addSAlexander Pyhalov * a string known to occur in the pattern. We can then 869d2d52addSAlexander Pyhalov * do a BMG match on the whole buffer. 870d2d52addSAlexander Pyhalov * This is an order of magnitude faster. 871d2d52addSAlexander Pyhalov * Otherwise we split the buffer into lines, 872d2d52addSAlexander Pyhalov * and check for a match on each line. 873d2d52addSAlexander Pyhalov */ 874d2d52addSAlexander Pyhalov static int 875d2d52addSAlexander Pyhalov grep(int fd, const char *fn) 876d2d52addSAlexander Pyhalov { 877d2d52addSAlexander Pyhalov PATTERN *pp; 878d2d52addSAlexander Pyhalov off_t data_len; /* length of the data chunk */ 879d2d52addSAlexander Pyhalov off_t line_len; /* length of the current line */ 880d2d52addSAlexander Pyhalov off_t line_offset; /* current line's offset from the beginning */ 881d2d52addSAlexander Pyhalov off_t blkoffset; /* line_offset but context-compatible */ 882d2d52addSAlexander Pyhalov long long lineno, linenum; 883d2d52addSAlexander Pyhalov long long matches = 0; /* Number of matching lines */ 8844adc6f15SPeter Tribble long long conacnt = 0, conbcnt = 0; /* context line count */ 885d2d52addSAlexander Pyhalov int newlinep; /* 0 if the last line of file has no newline */ 886d2d52addSAlexander Pyhalov char *ptr, *ptrend, *prntptr, *prntptrend; 887d2d52addSAlexander Pyhalov char *nextptr = NULL, *nextend = NULL; 888d2d52addSAlexander Pyhalov char *conptr = NULL, *conptrend = NULL; 889d2d52addSAlexander Pyhalov char *matchptr = NULL; 890d2d52addSAlexander Pyhalov int conaprnt = 0, conbprnt = 0, lastmatch = 0; 891d2d52addSAlexander Pyhalov boolean_t nearmatch; /* w/in N+1 of last match */ 892d2d52addSAlexander Pyhalov boolean_t havematch = B_FALSE; /* have a match in context */ 893*81dd18d8SRobert Mustacchi boolean_t sameline = B_FALSE; /* Are we still on the same line? */ 894d2d52addSAlexander Pyhalov size_t prntlen; 895d2d52addSAlexander Pyhalov 896d2d52addSAlexander Pyhalov if (patterns == NULL) 897d2d52addSAlexander Pyhalov return (0); /* no patterns to match -- just return */ 898d2d52addSAlexander Pyhalov 899d2d52addSAlexander Pyhalov pp = patterns; 900d2d52addSAlexander Pyhalov 901d2d52addSAlexander Pyhalov if (use_bmg) { 902d2d52addSAlexander Pyhalov bmgcomp(pp->pattern, strlen(pp->pattern)); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 905d2d52addSAlexander Pyhalov if (prntbuf == NULL) { 906d2d52addSAlexander Pyhalov prntbuflen = BUFSIZE; 907d2d52addSAlexander Pyhalov if ((prntbuf = malloc(prntbuflen + 1)) == NULL) { 908d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"), 909d2d52addSAlexander Pyhalov cmdname); 910d2d52addSAlexander Pyhalov exit(2); 911d2d52addSAlexander Pyhalov } 912d2d52addSAlexander Pyhalov } 913d2d52addSAlexander Pyhalov 914d2d52addSAlexander Pyhalov if (conflag != 0 && (conbuf == NULL)) { 915d2d52addSAlexander Pyhalov conbuflen = BUFSIZE; 916d2d52addSAlexander Pyhalov if ((conbuf = malloc(BUFSIZE+1)) == NULL) { 917d2d52addSAlexander Pyhalov (void) fprintf(stderr, gettext("%s: out of memory\n"), 918d2d52addSAlexander Pyhalov cmdname); 919d2d52addSAlexander Pyhalov exit(2); 920d2d52addSAlexander Pyhalov } 921d2d52addSAlexander Pyhalov } 9227c478bd9Sstevel@tonic-gate 923d2d52addSAlexander Pyhalov nearmatch = (conmatches != 0); 924d2d52addSAlexander Pyhalov blkoffset = line_offset = 0; 925d2d52addSAlexander Pyhalov lineno = 0; 926d2d52addSAlexander Pyhalov linenum = 1; 927d2d52addSAlexander Pyhalov newlinep = 1; 928d2d52addSAlexander Pyhalov data_len = 0; 929d2d52addSAlexander Pyhalov for (; ; ) { 930d2d52addSAlexander Pyhalov long count; 931d2d52addSAlexander Pyhalov off_t offset = 0; 932d2d52addSAlexander Pyhalov char separate; 933*81dd18d8SRobert Mustacchi char *startmatch = NULL; /* -o, start of match */ 934*81dd18d8SRobert Mustacchi char *postmatch = NULL; /* -o, character after match */ 935d2d52addSAlexander Pyhalov boolean_t last_ctx = B_FALSE, eof = B_FALSE; 936d2d52addSAlexander Pyhalov 937d2d52addSAlexander Pyhalov if (data_len == 0) { 938d2d52addSAlexander Pyhalov /* 939d2d52addSAlexander Pyhalov * If no data in the buffer, reset ptr 940d2d52addSAlexander Pyhalov */ 941d2d52addSAlexander Pyhalov ptr = prntbuf; 942d2d52addSAlexander Pyhalov if (conflag != 0 && conptr == NULL) { 943d2d52addSAlexander Pyhalov conptr = conbuf; 944d2d52addSAlexander Pyhalov conptrend = conptr - 1; 945d2d52addSAlexander Pyhalov } 946d2d52addSAlexander Pyhalov } 947d2d52addSAlexander Pyhalov if (ptr == prntbuf) { 9487c478bd9Sstevel@tonic-gate /* 949d2d52addSAlexander Pyhalov * The current data chunk starts from prntbuf. 950d2d52addSAlexander Pyhalov * This means either the buffer has no data 951d2d52addSAlexander Pyhalov * or the buffer has no newline. 952d2d52addSAlexander Pyhalov * So, read more data from input. 9537c478bd9Sstevel@tonic-gate */ 954d2d52addSAlexander Pyhalov count = read(fd, ptr + data_len, prntbuflen - data_len); 955d2d52addSAlexander Pyhalov if (count < 0) { 956d2d52addSAlexander Pyhalov /* read error */ 957d2d52addSAlexander Pyhalov if (cflag) { 958d2d52addSAlexander Pyhalov if (outfn && !rflag) { 959d2d52addSAlexander Pyhalov (void) fprintf(stdout, 960d2d52addSAlexander Pyhalov "%s:", fn); 961d2d52addSAlexander Pyhalov } 962d2d52addSAlexander Pyhalov if (!qflag && !rflag) { 963d2d52addSAlexander Pyhalov (void) fprintf(stdout, "%lld\n", 964d2d52addSAlexander Pyhalov matches); 965d2d52addSAlexander Pyhalov } 966d2d52addSAlexander Pyhalov } 967d2d52addSAlexander Pyhalov return (0); 968d2d52addSAlexander Pyhalov } else if (count == 0) { 969d2d52addSAlexander Pyhalov /* no new data */ 970d2d52addSAlexander Pyhalov eof = B_TRUE; 971d2d52addSAlexander Pyhalov 972d2d52addSAlexander Pyhalov if (data_len == 0) { 973d2d52addSAlexander Pyhalov /* end of file already reached */ 974d2d52addSAlexander Pyhalov if (conflag != 0) { 975d2d52addSAlexander Pyhalov if (conptrend >= conptr) 976d2d52addSAlexander Pyhalov *conptrend = '\n'; 977d2d52addSAlexander Pyhalov last_ctx = B_TRUE; 978d2d52addSAlexander Pyhalov goto L_next_line; 979d2d52addSAlexander Pyhalov } else { 980d2d52addSAlexander Pyhalov goto out; 981d2d52addSAlexander Pyhalov } 982d2d52addSAlexander Pyhalov } 983d2d52addSAlexander Pyhalov /* last line of file has no newline */ 984d2d52addSAlexander Pyhalov ptrend = ptr + data_len; 985d2d52addSAlexander Pyhalov newlinep = 0; 986d2d52addSAlexander Pyhalov goto L_start_process; 987d2d52addSAlexander Pyhalov } 988d2d52addSAlexander Pyhalov offset = data_len; 989d2d52addSAlexander Pyhalov data_len += count; 990d2d52addSAlexander Pyhalov } 991d2d52addSAlexander Pyhalov 992d2d52addSAlexander Pyhalov /* 993d2d52addSAlexander Pyhalov * Look for newline in the chunk 994d2d52addSAlexander Pyhalov * between ptr + offset and ptr + data_len - offset. 995d2d52addSAlexander Pyhalov */ 996d2d52addSAlexander Pyhalov ptrend = find_nl(ptr + offset, data_len - offset); 997d2d52addSAlexander Pyhalov if (ptrend == NULL) { 998d2d52addSAlexander Pyhalov /* no newline found in this chunk */ 9997c478bd9Sstevel@tonic-gate if (ptr > prntbuf) { 1000d2d52addSAlexander Pyhalov /* 1001d2d52addSAlexander Pyhalov * Move remaining data to the beginning 1002d2d52addSAlexander Pyhalov * of the buffer. 1003d2d52addSAlexander Pyhalov * Remaining data lie from ptr for 1004d2d52addSAlexander Pyhalov * data_len bytes. 1005d2d52addSAlexander Pyhalov */ 1006d2d52addSAlexander Pyhalov (void) memmove(prntbuf, ptr, data_len); 10077c478bd9Sstevel@tonic-gate } 1008d2d52addSAlexander Pyhalov if (data_len == prntbuflen) { 1009d2d52addSAlexander Pyhalov /* 1010d2d52addSAlexander Pyhalov * Not enough room in the buffer 1011d2d52addSAlexander Pyhalov */ 1012d2d52addSAlexander Pyhalov if (prntbuflen > SIZE_MAX - BUFSIZE) { 1013d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1014d2d52addSAlexander Pyhalov gettext("%s: buflen would" 1015d2d52addSAlexander Pyhalov " overflow\n"), 1016d2d52addSAlexander Pyhalov cmdname); 1017d2d52addSAlexander Pyhalov exit(2); 1018d2d52addSAlexander Pyhalov } 1019d2d52addSAlexander Pyhalov 1020d2d52addSAlexander Pyhalov prntbuflen += BUFSIZE; 1021d2d52addSAlexander Pyhalov prntbuf = realloc(prntbuf, prntbuflen + 1); 1022d2d52addSAlexander Pyhalov if (prntbuf == NULL) { 1023d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1024d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 1025d2d52addSAlexander Pyhalov cmdname); 1026d2d52addSAlexander Pyhalov exit(2); 1027d2d52addSAlexander Pyhalov } 1028d2d52addSAlexander Pyhalov } 1029d2d52addSAlexander Pyhalov ptr = prntbuf; 1030d2d52addSAlexander Pyhalov /* read the next input */ 1031d2d52addSAlexander Pyhalov continue; 1032d2d52addSAlexander Pyhalov } 1033d2d52addSAlexander Pyhalov L_start_process: 10347c478bd9Sstevel@tonic-gate 1035d2d52addSAlexander Pyhalov /* 1036d2d52addSAlexander Pyhalov * Beginning of the chunk: ptr 1037d2d52addSAlexander Pyhalov * End of the chunk: ptr + data_len 1038d2d52addSAlexander Pyhalov * Beginning of the line: ptr 1039d2d52addSAlexander Pyhalov * End of the line: ptrend 1040d2d52addSAlexander Pyhalov * 1041d2d52addSAlexander Pyhalov * conptr: Beginning of the context. 1042d2d52addSAlexander Pyhalov * conptrend: If context is empty, conptr - 1 (invalid memory). 1043d2d52addSAlexander Pyhalov * Otherwise, Last newline in the context. 1044d2d52addSAlexander Pyhalov */ 1045d2d52addSAlexander Pyhalov 1046d2d52addSAlexander Pyhalov if (use_bmg) { 10477c478bd9Sstevel@tonic-gate /* 1048d2d52addSAlexander Pyhalov * Use Boyer-Moore-Gosper algorithm to find out if 1049d2d52addSAlexander Pyhalov * this chunk (not this line) contains the specified 1050d2d52addSAlexander Pyhalov * pattern. If not, restart from the last line 1051d2d52addSAlexander Pyhalov * of this chunk. 10527c478bd9Sstevel@tonic-gate */ 1053d2d52addSAlexander Pyhalov char *bline; 1054d2d52addSAlexander Pyhalov bline = bmgexec(ptr, ptr + data_len); 1055d2d52addSAlexander Pyhalov if (bline == NULL) { 10567c478bd9Sstevel@tonic-gate /* 1057d2d52addSAlexander Pyhalov * No pattern found in this chunk. 1058d2d52addSAlexander Pyhalov * Need to find the last line 1059d2d52addSAlexander Pyhalov * in this chunk. 10607c478bd9Sstevel@tonic-gate */ 1061d2d52addSAlexander Pyhalov ptrend = rfind_nl(ptr, data_len); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* 1064d2d52addSAlexander Pyhalov * When this chunk does not contain newline, 1065d2d52addSAlexander Pyhalov * ptrend becomes NULL, which should happen 1066d2d52addSAlexander Pyhalov * when the last line of file does not end 1067d2d52addSAlexander Pyhalov * with a newline. At such a point, 1068d2d52addSAlexander Pyhalov * newlinep should have been set to 0. 1069d2d52addSAlexander Pyhalov * Therefore, just after jumping to 1070d2d52addSAlexander Pyhalov * L_skip_line, the main for-loop quits, 1071d2d52addSAlexander Pyhalov * and the line_len value won't be 1072d2d52addSAlexander Pyhalov * used. 1073d2d52addSAlexander Pyhalov */ 1074d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1075d2d52addSAlexander Pyhalov goto L_skip_line; 1076d2d52addSAlexander Pyhalov } 1077d2d52addSAlexander Pyhalov if (bline > ptrend) { 1078d2d52addSAlexander Pyhalov /* 1079d2d52addSAlexander Pyhalov * Pattern found not in the first line 1080d2d52addSAlexander Pyhalov * of this chunk. 1081d2d52addSAlexander Pyhalov * Discard the first line. 10827c478bd9Sstevel@tonic-gate */ 1083d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1084d2d52addSAlexander Pyhalov goto L_skip_line; 1085d2d52addSAlexander Pyhalov } 1086d2d52addSAlexander Pyhalov /* 1087d2d52addSAlexander Pyhalov * Pattern found in the first line of this chunk. 1088d2d52addSAlexander Pyhalov * Using this result. 1089d2d52addSAlexander Pyhalov */ 1090d2d52addSAlexander Pyhalov *ptrend = '\0'; 1091d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1092d2d52addSAlexander Pyhalov 1093d2d52addSAlexander Pyhalov /* 1094d2d52addSAlexander Pyhalov * before jumping to L_next_line, 1095d2d52addSAlexander Pyhalov * need to handle xflag if specified 1096d2d52addSAlexander Pyhalov */ 1097d2d52addSAlexander Pyhalov if (xflag && (line_len != bmglen || 1098d2d52addSAlexander Pyhalov strcmp(bmgpat, ptr) != 0)) { 1099d2d52addSAlexander Pyhalov /* didn't match */ 1100d2d52addSAlexander Pyhalov pp = NULL; 1101d2d52addSAlexander Pyhalov } else { 1102d2d52addSAlexander Pyhalov pp = patterns; /* to make it happen */ 1103d2d52addSAlexander Pyhalov } 1104d2d52addSAlexander Pyhalov goto L_next_line; 1105d2d52addSAlexander Pyhalov } 1106*81dd18d8SRobert Mustacchi 1107*81dd18d8SRobert Mustacchi /* 1108*81dd18d8SRobert Mustacchi * When using -o, we might actually loop around while still on 1109*81dd18d8SRobert Mustacchi * the same line. In such a case, we need to make sure we don't 1110*81dd18d8SRobert Mustacchi * increment the line number. 1111*81dd18d8SRobert Mustacchi */ 1112*81dd18d8SRobert Mustacchi if (!sameline) { 1113*81dd18d8SRobert Mustacchi lineno++; 1114*81dd18d8SRobert Mustacchi } else { 1115*81dd18d8SRobert Mustacchi sameline = B_FALSE; 1116*81dd18d8SRobert Mustacchi } 1117*81dd18d8SRobert Mustacchi 1118d2d52addSAlexander Pyhalov /* 1119d2d52addSAlexander Pyhalov * Line starts from ptr and ends at ptrend. 1120d2d52addSAlexander Pyhalov * line_len will be the length of the line. 1121d2d52addSAlexander Pyhalov */ 1122d2d52addSAlexander Pyhalov *ptrend = '\0'; 1123d2d52addSAlexander Pyhalov line_len = ptrend - ptr; 1124d2d52addSAlexander Pyhalov 1125d2d52addSAlexander Pyhalov /* 1126d2d52addSAlexander Pyhalov * From now, the process will be performed based 1127d2d52addSAlexander Pyhalov * on the line from ptr to ptrend. 1128d2d52addSAlexander Pyhalov */ 1129*81dd18d8SRobert Mustacchi for (pp = patterns; pp; pp = pp->next) { 1130*81dd18d8SRobert Mustacchi int rv; 1131*81dd18d8SRobert Mustacchi regmatch_t rm; 1132*81dd18d8SRobert Mustacchi size_t nmatch = 0; 11337c478bd9Sstevel@tonic-gate 1134*81dd18d8SRobert Mustacchi /* 1135*81dd18d8SRobert Mustacchi * The current implementation of regexec has a higher 1136*81dd18d8SRobert Mustacchi * cost when you ask for match information. As a result, 1137*81dd18d8SRobert Mustacchi * we only ask for a match when we know that we need it 1138*81dd18d8SRobert Mustacchi * specifically. This is always needed for -o because we 1139*81dd18d8SRobert Mustacchi * rely on it to tell us what we matched. For fgrep -x 1140*81dd18d8SRobert Mustacchi * we need it so we can determine whether we matched the 1141*81dd18d8SRobert Mustacchi * entire line. 1142*81dd18d8SRobert Mustacchi */ 1143*81dd18d8SRobert Mustacchi if (oflag || (Fflag && xflag)) 1144*81dd18d8SRobert Mustacchi nmatch = 1; 11457c478bd9Sstevel@tonic-gate 1146*81dd18d8SRobert Mustacchi rv = regexec(&pp->re, ptr, nmatch, &rm, 0); 1147*81dd18d8SRobert Mustacchi if (rv == REG_OK) { 1148*81dd18d8SRobert Mustacchi /* 1149*81dd18d8SRobert Mustacchi * fgrep in this form cannot insert the 1150*81dd18d8SRobert Mustacchi * metacharacters to verify whether or not we 1151*81dd18d8SRobert Mustacchi * were the entire line. As a result, we check 1152*81dd18d8SRobert Mustacchi * the pattern length against the line length. 1153*81dd18d8SRobert Mustacchi */ 1154*81dd18d8SRobert Mustacchi if (Fflag && xflag && 1155*81dd18d8SRobert Mustacchi line_len != rm.rm_eo - rm.rm_so) { 1156*81dd18d8SRobert Mustacchi continue; 1157d2d52addSAlexander Pyhalov } 11587c478bd9Sstevel@tonic-gate 1159*81dd18d8SRobert Mustacchi /* matched */ 1160*81dd18d8SRobert Mustacchi if (oflag) { 1161*81dd18d8SRobert Mustacchi startmatch = ptr + rm.rm_so; 1162*81dd18d8SRobert Mustacchi postmatch = ptr + rm.rm_eo; 1163d2d52addSAlexander Pyhalov } 1164*81dd18d8SRobert Mustacchi break; 1165d2d52addSAlexander Pyhalov } 1166d2d52addSAlexander Pyhalov 1167*81dd18d8SRobert Mustacchi switch (rv) { 1168*81dd18d8SRobert Mustacchi case REG_NOMATCH: 1169*81dd18d8SRobert Mustacchi break; 1170*81dd18d8SRobert Mustacchi case REG_ECHAR: 1171*81dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext( 1172d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: invalid multibyte character\n"), 1173*81dd18d8SRobert Mustacchi cmdname, fn, lineno); 1174*81dd18d8SRobert Mustacchi break; 1175*81dd18d8SRobert Mustacchi default: 1176*81dd18d8SRobert Mustacchi (void) regerror(rv, &pp->re, errstr, 1177*81dd18d8SRobert Mustacchi sizeof (errstr)); 1178*81dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext( 1179d2d52addSAlexander Pyhalov "%s: input file \"%s\": line %lld: %s\n"), 1180*81dd18d8SRobert Mustacchi cmdname, fn, lineno, errstr); 1181*81dd18d8SRobert Mustacchi exit(2); 1182d2d52addSAlexander Pyhalov } 1183d2d52addSAlexander Pyhalov } 1184d2d52addSAlexander Pyhalov 1185d2d52addSAlexander Pyhalov /* 1186d2d52addSAlexander Pyhalov * Context is set up as follows: 1187d2d52addSAlexander Pyhalov * For a 'Before' context, we maintain a set of pointers 1188d2d52addSAlexander Pyhalov * containing 'N' lines of context. If the current number of 1189d2d52addSAlexander Pyhalov * lines contained is greater than N, and N isn't a match, the 1190d2d52addSAlexander Pyhalov * start pointer is moved forward to the next newline. 1191d2d52addSAlexander Pyhalov * 1192d2d52addSAlexander Pyhalov * If we ever find a match, we print out immediately. 1193d2d52addSAlexander Pyhalov * 'nearmatch' tells us if we're within N+1 lines of the last 1194d2d52addSAlexander Pyhalov * match ; if we are, and we find another match, we don't 1195d2d52addSAlexander Pyhalov * separate the matches. 'nearmatch' becomes false when 1196d2d52addSAlexander Pyhalov * a line gets rotated out of the context. 1197d2d52addSAlexander Pyhalov * 1198d2d52addSAlexander Pyhalov * For an 'After' context, we simply wait until we've found a 1199d2d52addSAlexander Pyhalov * match, then create a context N+1 lines big. If we don't find 1200d2d52addSAlexander Pyhalov * a match within the context, we print out the current context. 1201d2d52addSAlexander Pyhalov * Otherwise, we save a reference to the new matching line, 1202d2d52addSAlexander Pyhalov * print out the other context, and reset our context pointers 1203d2d52addSAlexander Pyhalov * to the new matching line. 1204d2d52addSAlexander Pyhalov * 1205d2d52addSAlexander Pyhalov * 'nearmatch' becomes false when we find a non-matching line 1206d2d52addSAlexander Pyhalov * that isn't a part of any context. 1207d2d52addSAlexander Pyhalov * 1208d2d52addSAlexander Pyhalov * A full-context is implemented as a combination of the 1209d2d52addSAlexander Pyhalov * 'Before' and 'After' context logic. Before we find a match, 1210d2d52addSAlexander Pyhalov * we follow the Before logic. When we find a match, we 1211d2d52addSAlexander Pyhalov * follow the After logic. 'nearmatch' is handled by the Before 1212d2d52addSAlexander Pyhalov * logic. 1213d2d52addSAlexander Pyhalov */ 1214d2d52addSAlexander Pyhalov 1215d2d52addSAlexander Pyhalov if (conflag == 0) 1216d2d52addSAlexander Pyhalov goto L_next_line; 1217d2d52addSAlexander Pyhalov 1218d2d52addSAlexander Pyhalov /* Do we have room to add this line to the context buffer? */ 1219d9241f99SAndrew Stormont while ((line_len + 1) > (conbuflen - 1220d9241f99SAndrew Stormont ((conptrend >= conptr) ? conptrend - conbuf : 0))) { 1221d2d52addSAlexander Pyhalov char *oldconbuf = conbuf; 1222d2d52addSAlexander Pyhalov char *oldconptr = conptr; 1223d2d52addSAlexander Pyhalov long tmp = matchptr - conptr; 1224d2d52addSAlexander Pyhalov 1225d2d52addSAlexander Pyhalov if (conbuflen > SIZE_MAX - BUFSIZE) { 1226d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1227d2d52addSAlexander Pyhalov gettext("%s: buflen would overflow\n"), 1228d2d52addSAlexander Pyhalov cmdname); 1229d2d52addSAlexander Pyhalov exit(2); 1230d2d52addSAlexander Pyhalov } 1231d2d52addSAlexander Pyhalov 1232d2d52addSAlexander Pyhalov conbuflen += BUFSIZE; 1233d2d52addSAlexander Pyhalov conbuf = realloc(conbuf, conbuflen + 1); 1234d2d52addSAlexander Pyhalov if (conbuf == NULL) { 1235d2d52addSAlexander Pyhalov (void) fprintf(stderr, 1236d2d52addSAlexander Pyhalov gettext("%s: out of memory\n"), 1237d2d52addSAlexander Pyhalov cmdname); 1238d2d52addSAlexander Pyhalov exit(2); 1239d2d52addSAlexander Pyhalov } 1240d2d52addSAlexander Pyhalov 1241d2d52addSAlexander Pyhalov conptr = conbuf + (conptr - oldconbuf); 1242d2d52addSAlexander Pyhalov conptrend = conptr + (conptrend - oldconptr); 1243d2d52addSAlexander Pyhalov if (matchptr) 1244d2d52addSAlexander Pyhalov matchptr = conptr + tmp; 1245d2d52addSAlexander Pyhalov } 1246d2d52addSAlexander Pyhalov (void) memcpy(conptrend + 1, ptr, line_len); 1247d2d52addSAlexander Pyhalov conptrend += line_len + 1; 1248d2d52addSAlexander Pyhalov *conptrend = '\n'; 1249d2d52addSAlexander Pyhalov 1250d2d52addSAlexander Pyhalov if (nvflag == (pp != NULL)) { 1251d2d52addSAlexander Pyhalov /* matched */ 1252d2d52addSAlexander Pyhalov if (havematch) { 1253d2d52addSAlexander Pyhalov if ((conflag & AFTER) != 0) { 1254d2d52addSAlexander Pyhalov conaprnt = 1; 1255d2d52addSAlexander Pyhalov nextend = conptrend; 1256d2d52addSAlexander Pyhalov conptrend = conptr + lastmatch; 1257d2d52addSAlexander Pyhalov nextptr = conptrend + 1; 1258d2d52addSAlexander Pyhalov *nextend = '\n'; 1259d2d52addSAlexander Pyhalov } 1260d2d52addSAlexander Pyhalov } else { 1261d2d52addSAlexander Pyhalov if (conflag == AFTER) { 1262d2d52addSAlexander Pyhalov conptr = conptrend - (line_len); 1263d2d52addSAlexander Pyhalov linenum = lineno; 1264d2d52addSAlexander Pyhalov } 1265d2d52addSAlexander Pyhalov blkoffset = line_offset - 1266d2d52addSAlexander Pyhalov (conptrend - conptr - line_len); 1267d2d52addSAlexander Pyhalov } 1268d2d52addSAlexander Pyhalov 1269d2d52addSAlexander Pyhalov if (conflag == BEFORE) 1270d2d52addSAlexander Pyhalov conbprnt = 1; 1271d2d52addSAlexander Pyhalov 1272d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr; 1273d2d52addSAlexander Pyhalov havematch = B_TRUE; 1274d2d52addSAlexander Pyhalov goto L_next_line; 1275d2d52addSAlexander Pyhalov } 1276d2d52addSAlexander Pyhalov 1277d2d52addSAlexander Pyhalov if (!havematch) { 1278d2d52addSAlexander Pyhalov if ((conflag & BEFORE) != 0) { 1279d2d52addSAlexander Pyhalov if (conbcnt >= conblen) { 1280d2d52addSAlexander Pyhalov char *tmp = conptr; 1281d2d52addSAlexander Pyhalov conptr = find_nl(conptr, 1282d2d52addSAlexander Pyhalov conptrend - conptr) + 1; 1283d2d52addSAlexander Pyhalov if (bflag) 1284d2d52addSAlexander Pyhalov blkoffset += conptr - tmp; 1285d2d52addSAlexander Pyhalov linenum++; 1286d2d52addSAlexander Pyhalov nearmatch = B_TRUE; 1287d2d52addSAlexander Pyhalov } else { 1288d2d52addSAlexander Pyhalov conbcnt++; 1289d2d52addSAlexander Pyhalov } 1290d2d52addSAlexander Pyhalov } 1291d2d52addSAlexander Pyhalov if (conflag == AFTER) 1292d2d52addSAlexander Pyhalov nearmatch = B_TRUE; 1293d2d52addSAlexander Pyhalov } else { 1294d2d52addSAlexander Pyhalov if (++conacnt >= conalen && !conaprnt && conalen) 1295d2d52addSAlexander Pyhalov conaprnt = 1; 1296d2d52addSAlexander Pyhalov else 1297d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr; 1298d2d52addSAlexander Pyhalov } 1299d2d52addSAlexander Pyhalov 1300d2d52addSAlexander Pyhalov L_next_line: 1301d2d52addSAlexander Pyhalov /* 1302d2d52addSAlexander Pyhalov * Here, if pp points to non-NULL, something has been matched 1303d2d52addSAlexander Pyhalov * to the pattern. 1304d2d52addSAlexander Pyhalov */ 1305d2d52addSAlexander Pyhalov if (!last_ctx && nvflag == (pp != NULL)) { 1306d2d52addSAlexander Pyhalov matches++; 1307*81dd18d8SRobert Mustacchi if (!nextend) { 1308*81dd18d8SRobert Mustacchi if (conflag != 0) { 1309*81dd18d8SRobert Mustacchi matchptr = conptrend; 1310*81dd18d8SRobert Mustacchi } else if (oflag) { 1311*81dd18d8SRobert Mustacchi matchptr = postmatch - 1; 1312*81dd18d8SRobert Mustacchi } else { 1313*81dd18d8SRobert Mustacchi matchptr = ptrend; 1314*81dd18d8SRobert Mustacchi } 1315*81dd18d8SRobert Mustacchi } 1316*81dd18d8SRobert Mustacchi } 1317*81dd18d8SRobert Mustacchi 1318*81dd18d8SRobert Mustacchi if (pp != NULL && oflag && postmatch == NULL) { 1319*81dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext("%s: internal error, " 1320*81dd18d8SRobert Mustacchi "-o set, but failed to find postmatch\n"), cmdname); 1321*81dd18d8SRobert Mustacchi abort(); 1322d2d52addSAlexander Pyhalov } 1323d2d52addSAlexander Pyhalov 1324d2d52addSAlexander Pyhalov /* 1325d2d52addSAlexander Pyhalov * Set up some print context so that we can treat 1326d2d52addSAlexander Pyhalov * single-line matches as a zero-N context. 1327d2d52addSAlexander Pyhalov * Apply CLI flags to each line of the context. 1328d2d52addSAlexander Pyhalov * 1329d2d52addSAlexander Pyhalov * For context, we only print if we both have a match and are 1330d2d52addSAlexander Pyhalov * either at the end of the data stream, or we've previously 1331d2d52addSAlexander Pyhalov * declared that we want to print for a particular context. 1332d2d52addSAlexander Pyhalov */ 1333d2d52addSAlexander Pyhalov if (havematch && (eof || conaprnt || conbprnt)) { 1334d2d52addSAlexander Pyhalov 1335d2d52addSAlexander Pyhalov /* 1336d2d52addSAlexander Pyhalov * We'd normally do this earlier, but we had to 1337d2d52addSAlexander Pyhalov * escape early because we reached the end of the data. 1338d2d52addSAlexander Pyhalov */ 1339d2d52addSAlexander Pyhalov if (eof && nextptr) 1340d2d52addSAlexander Pyhalov conptrend = nextend; 1341d2d52addSAlexander Pyhalov 1342d2d52addSAlexander Pyhalov prntlen = conptrend - conptr + 1; 1343d2d52addSAlexander Pyhalov prntptr = conptr; 1344d2d52addSAlexander Pyhalov if (conmatches++ && nearmatch && !cflag) 1345d2d52addSAlexander Pyhalov (void) fwrite("--\n", 1, 3, stdout); 1346d2d52addSAlexander Pyhalov } else if (conflag == 0 && nvflag == (pp != NULL)) { 1347d2d52addSAlexander Pyhalov *ptrend = '\n'; 1348*81dd18d8SRobert Mustacchi if (oflag) { 1349*81dd18d8SRobert Mustacchi prntptr = startmatch; 1350*81dd18d8SRobert Mustacchi } else { 1351*81dd18d8SRobert Mustacchi prntptr = ptr; 1352*81dd18d8SRobert Mustacchi } 1353d2d52addSAlexander Pyhalov prntlen = line_len + 1; 1354d2d52addSAlexander Pyhalov linenum = lineno; 1355d2d52addSAlexander Pyhalov blkoffset = line_offset; 1356*81dd18d8SRobert Mustacchi if (oflag) { 1357*81dd18d8SRobert Mustacchi blkoffset += startmatch - ptr; 1358*81dd18d8SRobert Mustacchi } 1359d2d52addSAlexander Pyhalov } else if (eof) { 1360d2d52addSAlexander Pyhalov /* No match and no more data */ 1361d2d52addSAlexander Pyhalov goto out; 13627c478bd9Sstevel@tonic-gate } else { 1363d2d52addSAlexander Pyhalov /* No match, or we're not done building context */ 1364d2d52addSAlexander Pyhalov goto L_skip_line; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate 1367*81dd18d8SRobert Mustacchi if (oflag) { 1368*81dd18d8SRobert Mustacchi prntptrend = postmatch - 1; 1369*81dd18d8SRobert Mustacchi } else { 1370*81dd18d8SRobert Mustacchi prntptrend = prntptr - 1; 1371*81dd18d8SRobert Mustacchi } 1372*81dd18d8SRobert Mustacchi while (oflag || (prntptrend = find_nl(prntptrend + 1, 1373d2d52addSAlexander Pyhalov prntlen)) != NULL) { 13747c478bd9Sstevel@tonic-gate /* 1375d2d52addSAlexander Pyhalov * GNU grep uses '-' for context lines and ':' for 1376d2d52addSAlexander Pyhalov * matching lines, so replicate that here. 13777c478bd9Sstevel@tonic-gate */ 1378d2d52addSAlexander Pyhalov if (prntptrend == matchptr) { 1379d2d52addSAlexander Pyhalov if (eof && nextptr) { 1380d2d52addSAlexander Pyhalov matchptr = nextend; 1381d2d52addSAlexander Pyhalov nextptr = NULL; 1382d2d52addSAlexander Pyhalov } else { 1383d2d52addSAlexander Pyhalov matchptr = NULL; 1384d2d52addSAlexander Pyhalov } 1385d2d52addSAlexander Pyhalov separate = ':'; 1386d2d52addSAlexander Pyhalov } else { 1387d2d52addSAlexander Pyhalov separate = '-'; 1388d2d52addSAlexander Pyhalov } 1389d2d52addSAlexander Pyhalov 13907c478bd9Sstevel@tonic-gate /* 1391d2d52addSAlexander Pyhalov * Handle q, l, and c flags. 13927c478bd9Sstevel@tonic-gate */ 1393d2d52addSAlexander Pyhalov if (qflag) { 1394d2d52addSAlexander Pyhalov /* no need to continue */ 1395d2d52addSAlexander Pyhalov /* 1396d2d52addSAlexander Pyhalov * End of this line is ptrend. 1397d2d52addSAlexander Pyhalov * We have read up to ptr + data_len. 1398d2d52addSAlexander Pyhalov */ 1399d2d52addSAlexander Pyhalov off_t pos; 1400d2d52addSAlexander Pyhalov pos = ptr + data_len - (ptrend + 1); 1401d2d52addSAlexander Pyhalov (void) lseek(fd, -pos, SEEK_CUR); 1402d2d52addSAlexander Pyhalov exit(0); 1403d2d52addSAlexander Pyhalov } 1404d2d52addSAlexander Pyhalov if (lflag) { 1405d2d52addSAlexander Pyhalov (void) printf("%s\n", fn); 1406d2d52addSAlexander Pyhalov goto out; 1407d2d52addSAlexander Pyhalov } 14082e5ac464SRobert Mustacchi if (Lflag) { 14092e5ac464SRobert Mustacchi goto out; 14102e5ac464SRobert Mustacchi } 1411d2d52addSAlexander Pyhalov if (!cflag) { 1412d2d52addSAlexander Pyhalov if (Hflag || outfn) { 1413d2d52addSAlexander Pyhalov (void) printf("%s%c", fn, separate); 1414d2d52addSAlexander Pyhalov } 1415d2d52addSAlexander Pyhalov if (bflag) { 1416d2d52addSAlexander Pyhalov (void) printf("%lld%c", (offset_t) 1417d2d52addSAlexander Pyhalov (blkoffset / BSIZE), separate); 1418d2d52addSAlexander Pyhalov } 1419d2d52addSAlexander Pyhalov if (nflag) { 1420d2d52addSAlexander Pyhalov (void) printf("%lld%c", linenum, 1421d2d52addSAlexander Pyhalov separate); 1422d2d52addSAlexander Pyhalov } 1423d2d52addSAlexander Pyhalov (void) fwrite(prntptr, 1, 1424d2d52addSAlexander Pyhalov prntptrend - prntptr + 1, stdout); 1425*81dd18d8SRobert Mustacchi 1426*81dd18d8SRobert Mustacchi if (oflag) { 1427*81dd18d8SRobert Mustacchi (void) fputc('\n', stdout); 1428*81dd18d8SRobert Mustacchi } 1429d2d52addSAlexander Pyhalov } 1430d2d52addSAlexander Pyhalov if (ferror(stdout)) { 1431d2d52addSAlexander Pyhalov return (0); 1432d2d52addSAlexander Pyhalov } 1433*81dd18d8SRobert Mustacchi 1434*81dd18d8SRobert Mustacchi /* 1435*81dd18d8SRobert Mustacchi * With -o we'll only ever take this loop once. Manually 1436*81dd18d8SRobert Mustacchi * break out. 1437*81dd18d8SRobert Mustacchi */ 1438*81dd18d8SRobert Mustacchi if (oflag) { 1439*81dd18d8SRobert Mustacchi goto L_skip_line; 1440*81dd18d8SRobert Mustacchi } 1441*81dd18d8SRobert Mustacchi 1442d2d52addSAlexander Pyhalov linenum++; 1443d2d52addSAlexander Pyhalov prntlen -= prntptrend - prntptr + 1; 1444d2d52addSAlexander Pyhalov blkoffset += prntptrend - prntptr + 1; 1445d2d52addSAlexander Pyhalov prntptr = prntptrend + 1; 1446d2d52addSAlexander Pyhalov } 14477c478bd9Sstevel@tonic-gate 1448d2d52addSAlexander Pyhalov if (eof) 1449d2d52addSAlexander Pyhalov goto out; 1450d2d52addSAlexander Pyhalov 1451d2d52addSAlexander Pyhalov /* 1452d2d52addSAlexander Pyhalov * Update context buffer and variables post-print 1453d2d52addSAlexander Pyhalov */ 1454d2d52addSAlexander Pyhalov if (conflag != 0) { 1455d2d52addSAlexander Pyhalov conptr = conbuf; 1456d2d52addSAlexander Pyhalov conaprnt = conbprnt = 0; 1457d2d52addSAlexander Pyhalov nearmatch = B_FALSE; 1458d2d52addSAlexander Pyhalov conacnt = conbcnt = 0; 1459d2d52addSAlexander Pyhalov 1460d2d52addSAlexander Pyhalov if (nextptr) { 1461d2d52addSAlexander Pyhalov (void) memmove(conbuf, nextptr, 1462d2d52addSAlexander Pyhalov nextend - nextptr + 1); 1463d2d52addSAlexander Pyhalov blkoffset += nextptr - conptrend - 1; 1464d2d52addSAlexander Pyhalov conptrend = conptr + (nextend - nextptr); 1465d2d52addSAlexander Pyhalov matchptr = conptrend; 1466d2d52addSAlexander Pyhalov linenum = lineno; 1467d2d52addSAlexander Pyhalov lastmatch = conptrend - conptr; 1468d2d52addSAlexander Pyhalov havematch = B_TRUE; 1469d2d52addSAlexander Pyhalov } else { 1470d2d52addSAlexander Pyhalov conptrend = conptr - 1; 1471d2d52addSAlexander Pyhalov conacnt = 0; 1472d2d52addSAlexander Pyhalov lastmatch = 0; 1473d2d52addSAlexander Pyhalov havematch = B_FALSE; 1474d2d52addSAlexander Pyhalov } 1475d2d52addSAlexander Pyhalov nextptr = nextend = NULL; 1476d2d52addSAlexander Pyhalov } 14777c478bd9Sstevel@tonic-gate 1478d2d52addSAlexander Pyhalov L_skip_line: 1479d2d52addSAlexander Pyhalov if (!newlinep) 14807c478bd9Sstevel@tonic-gate break; 14817c478bd9Sstevel@tonic-gate 1482*81dd18d8SRobert Mustacchi if (oflag && postmatch != NULL) { 1483*81dd18d8SRobert Mustacchi line_len = postmatch - 1 - ptr; 1484*81dd18d8SRobert Mustacchi ptr = postmatch; 1485*81dd18d8SRobert Mustacchi sameline = B_TRUE; 1486*81dd18d8SRobert Mustacchi } else { 1487*81dd18d8SRobert Mustacchi ptr = ptrend + 1; 1488*81dd18d8SRobert Mustacchi } 1489d2d52addSAlexander Pyhalov data_len -= line_len + 1; 1490d2d52addSAlexander Pyhalov line_offset += line_len + 1; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 1493d2d52addSAlexander Pyhalov out: 1494d2d52addSAlexander Pyhalov if (cflag) { 1495d2d52addSAlexander Pyhalov if (Hflag || outfn) { 1496d2d52addSAlexander Pyhalov (void) printf("%s:", fn); 1497d2d52addSAlexander Pyhalov } 1498d2d52addSAlexander Pyhalov if (!qflag) { 1499d2d52addSAlexander Pyhalov (void) printf("%lld\n", matches); 1500d2d52addSAlexander Pyhalov } 15017c478bd9Sstevel@tonic-gate } 15022e5ac464SRobert Mustacchi 15032e5ac464SRobert Mustacchi /* 15042e5ac464SRobert Mustacchi * -L tells us to print the filename only when it doesn't match. So we 15052e5ac464SRobert Mustacchi * run through the normal operationa and then invert it. 15062e5ac464SRobert Mustacchi */ 15072e5ac464SRobert Mustacchi if (Lflag) { 15082e5ac464SRobert Mustacchi if (matches == 0) { 15092e5ac464SRobert Mustacchi (void) printf("%s\n", fn); 15102e5ac464SRobert Mustacchi matches = 1; 15112e5ac464SRobert Mustacchi } else { 15122e5ac464SRobert Mustacchi matches = 0; 15132e5ac464SRobert Mustacchi } 15142e5ac464SRobert Mustacchi } 15152e5ac464SRobert Mustacchi 1516d2d52addSAlexander Pyhalov return (matches != 0); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 1519d2d52addSAlexander Pyhalov /* 1520d2d52addSAlexander Pyhalov * usage message for grep 1521d2d52addSAlexander Pyhalov */ 1522d2d52addSAlexander Pyhalov static void 1523d2d52addSAlexander Pyhalov usage(void) 15247c478bd9Sstevel@tonic-gate { 1525e54e6a39SYuri Pankov (void) fprintf(stderr, gettext("usage: %5s"), cmdname); 1526e54e6a39SYuri Pankov if (!egrep && !fgrep) 1527e54e6a39SYuri Pankov (void) fprintf(stderr, gettext(" [-E|-F]")); 1528*81dd18d8SRobert Mustacchi (void) fprintf(stderr, gettext(" [-bchHilLnoqrRsvx] [-A num] [-B num] " 15298ccd0217SRobert Mustacchi "[-C num|-num]\n [--label=name] [-e pattern_list]... " 15308ccd0217SRobert Mustacchi "[-f pattern_file]...\n [pattern_list] [file]...\n")); 1531d2d52addSAlexander Pyhalov exit(2); 1532d2d52addSAlexander Pyhalov /* NOTREACHED */ 1533d2d52addSAlexander Pyhalov } 15347c478bd9Sstevel@tonic-gate 1535d2d52addSAlexander Pyhalov /* 1536d2d52addSAlexander Pyhalov * Compile literal pattern into BMG tables 1537d2d52addSAlexander Pyhalov */ 1538d2d52addSAlexander Pyhalov static void 1539d2d52addSAlexander Pyhalov bmgcomp(char *pat, int len) 1540d2d52addSAlexander Pyhalov { 1541d2d52addSAlexander Pyhalov int i; 1542d2d52addSAlexander Pyhalov int tlen; 1543d2d52addSAlexander Pyhalov unsigned char *uc = (unsigned char *)pat; 15447c478bd9Sstevel@tonic-gate 1545d2d52addSAlexander Pyhalov bmglen = len; 1546d2d52addSAlexander Pyhalov bmgpat = pat; 15477c478bd9Sstevel@tonic-gate 1548d2d52addSAlexander Pyhalov for (i = 0; i < M_CSETSIZE; i++) { 1549d2d52addSAlexander Pyhalov bmgtab[i] = len; 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 1552d2d52addSAlexander Pyhalov len--; 1553d2d52addSAlexander Pyhalov for (tlen = len, i = 0; i <= len; i++, tlen--) { 1554d2d52addSAlexander Pyhalov bmgtab[*uc++] = tlen; 1555d2d52addSAlexander Pyhalov } 15567c478bd9Sstevel@tonic-gate } 15577c478bd9Sstevel@tonic-gate 1558d2d52addSAlexander Pyhalov /* 1559d2d52addSAlexander Pyhalov * BMG search. 1560d2d52addSAlexander Pyhalov */ 1561d2d52addSAlexander Pyhalov static char * 1562d2d52addSAlexander Pyhalov bmgexec(char *str, char *end) 15637c478bd9Sstevel@tonic-gate { 1564d2d52addSAlexander Pyhalov int t; 1565d2d52addSAlexander Pyhalov char *k, *s, *p; 15667c478bd9Sstevel@tonic-gate 1567d2d52addSAlexander Pyhalov k = str + bmglen - 1; 1568d2d52addSAlexander Pyhalov if (bmglen == 1) { 1569d2d52addSAlexander Pyhalov return (memchr(str, bmgpat[0], end - str)); 1570d2d52addSAlexander Pyhalov } 1571d2d52addSAlexander Pyhalov for (; ; ) { 1572d2d52addSAlexander Pyhalov /* inner loop, should be most optimized */ 1573d2d52addSAlexander Pyhalov while (k < end && (t = bmgtab[(unsigned char)*k]) != 0) { 1574d2d52addSAlexander Pyhalov k += t; 1575d2d52addSAlexander Pyhalov } 1576d2d52addSAlexander Pyhalov if (k >= end) { 1577d2d52addSAlexander Pyhalov return (NULL); 1578d2d52addSAlexander Pyhalov } 1579d2d52addSAlexander Pyhalov for (s = k, p = bmgpat + bmglen - 1; *--s == *--p; ) { 1580d2d52addSAlexander Pyhalov if (p == bmgpat) { 1581d2d52addSAlexander Pyhalov return (s); 1582d2d52addSAlexander Pyhalov } 1583d2d52addSAlexander Pyhalov } 1584d2d52addSAlexander Pyhalov k++; 1585d2d52addSAlexander Pyhalov } 1586d2d52addSAlexander Pyhalov /* NOTREACHED */ 15877c478bd9Sstevel@tonic-gate } 1588