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