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