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