153451Speter/* grep.c - main driver file for grep. 2126435Sache Copyright 1992, 1997-1999, 2000 Free Software Foundation, Inc. 353451Speter 453451Speter This program is free software; you can redistribute it and/or modify 553451Speter it under the terms of the GNU General Public License as published by 653451Speter the Free Software Foundation; either version 2, or (at your option) 753451Speter any later version. 853451Speter 953451Speter This program is distributed in the hope that it will be useful, 1053451Speter but WITHOUT ANY WARRANTY; without even the implied warranty of 1153451Speter MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1253451Speter GNU General Public License for more details. 1353451Speter 1453451Speter You should have received a copy of the GNU General Public License 1553451Speter along with this program; if not, write to the Free Software 1653477Sobrien Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 1753477Sobrien 02111-1307, USA. */ 1853451Speter 1953477Sobrien/* Written July 1992 by Mike Haertel. */ 2053477Sobrien/* Builtin decompression 1997 by Wolfram Schneider <wosch@FreeBSD.org>. */ 2153451Speter 2253477Sobrien/* $FreeBSD$ */ 2353451Speter 2453477Sobrien#ifdef HAVE_CONFIG_H 2553477Sobrien# include <config.h> 2653451Speter#endif 2753451Speter#include <sys/types.h> 2853477Sobrien#include <sys/stat.h> 2953477Sobrien#if defined(HAVE_MMAP) 3053477Sobrien# include <sys/mman.h> 3153451Speter#endif 3253477Sobrien#if defined(HAVE_SETRLIMIT) 3353477Sobrien# include <sys/time.h> 3453477Sobrien# include <sys/resource.h> 3553451Speter#endif 36131564Stjr#if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H && defined HAVE_MBRTOWC 37131564Stjr/* We can handle multibyte string. */ 38131564Stjr# define MBS_SUPPORT 39131564Stjr# include <wchar.h> 40131564Stjr# include <wctype.h> 41131564Stjr#endif 4253477Sobrien#include <stdio.h> 4353477Sobrien#include "system.h" 4453477Sobrien#include "getopt.h" 4553451Speter#include "getpagesize.h" 4653451Speter#include "grep.h" 4753477Sobrien#include "savedir.h" 48131557Stjr#include "xstrtol.h" 49131557Stjr#include "xalloc.h" 50131557Stjr#include "error.h" 51131557Stjr#include "exclude.h" 52131557Stjr#include "closeout.h" 5353451Speter 5453451Speter#undef MAX 5553451Speter#define MAX(A,B) ((A) > (B) ? (A) : (B)) 5653451Speter 5753477Sobrienstruct stats 5853477Sobrien{ 59131557Stjr struct stats const *parent; 6053477Sobrien struct stat stat; 6153477Sobrien}; 6253451Speter 6353477Sobrien/* base of chain of stat buffers, used to detect directory loops */ 6453477Sobrienstatic struct stats stats_base; 6553451Speter 6653477Sobrien/* if non-zero, display usage information and exit */ 6753477Sobrienstatic int show_help; 6853451Speter 6953477Sobrien/* If non-zero, print the version on standard output and exit. */ 7053477Sobrienstatic int show_version; 7153451Speter 72131557Stjr/* If nonzero, suppress diagnostics for nonexistent or unreadable files. */ 73131557Stjrstatic int suppress_errors; 74131557Stjr 7555379Sobrien/* If nonzero, use mmap if possible. */ 7655379Sobrienstatic int mmap_option; 7755379Sobrien 7855404Sru/* If zero, output nulls after filenames. */ 7955404Srustatic int filename_mask; 8055404Sru 81131557Stjr/* If nonzero, use grep_color marker. */ 82131557Stjrstatic int color_option; 83131557Stjr 84131557Stjr/* If nonzero, show only the part of a line matching the expression. */ 85131557Stjrstatic int only_matching; 86131557Stjr 87131557Stjr/* The color string used. The user can overwrite it using the environment 88131557Stjr variable GREP_COLOR. The default is to print red. */ 89131557Stjrstatic const char *grep_color = "01;31"; 90131557Stjr 91131557Stjrstatic struct exclude *excluded_patterns; 92131557Stjrstatic struct exclude *included_patterns; 9355379Sobrien/* Short options. */ 9455379Sobrienstatic char const short_options[] = 95131557Stjr"0123456789A:B:C:D:EFGHIJPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz"; 9655379Sobrien 9756233Sru/* Non-boolean long options that have no corresponding short equivalents. */ 9856233Sruenum 9956233Sru{ 100131557Stjr BINARY_FILES_OPTION = CHAR_MAX + 1, 101131557Stjr COLOR_OPTION, 102131557Stjr INCLUDE_OPTION, 103131557Stjr EXCLUDE_OPTION, 104131557Stjr EXCLUDE_FROM_OPTION, 105131557Stjr LINE_BUFFERED_OPTION, 106131557Stjr LABEL_OPTION 10756233Sru}; 10856233Sru 10953477Sobrien/* Long options equivalences. */ 110131557Stjrstatic struct option const long_options[] = 11153477Sobrien{ 11253477Sobrien {"after-context", required_argument, NULL, 'A'}, 11353477Sobrien {"basic-regexp", no_argument, NULL, 'G'}, 11453477Sobrien {"before-context", required_argument, NULL, 'B'}, 11556233Sru {"binary-files", required_argument, NULL, BINARY_FILES_OPTION}, 11653477Sobrien {"byte-offset", no_argument, NULL, 'b'}, 117131557Stjr {"context", required_argument, NULL, 'C'}, 118131557Stjr {"color", optional_argument, NULL, COLOR_OPTION}, 119131557Stjr {"colour", optional_argument, NULL, COLOR_OPTION}, 12053477Sobrien {"count", no_argument, NULL, 'c'}, 121131557Stjr {"devices", required_argument, NULL, 'D'}, 12253477Sobrien {"directories", required_argument, NULL, 'd'}, 12353477Sobrien {"extended-regexp", no_argument, NULL, 'E'}, 124131557Stjr {"exclude", required_argument, NULL, EXCLUDE_OPTION}, 125131557Stjr {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION}, 12653477Sobrien {"file", required_argument, NULL, 'f'}, 12753477Sobrien {"files-with-matches", no_argument, NULL, 'l'}, 12853477Sobrien {"files-without-match", no_argument, NULL, 'L'}, 12953477Sobrien {"fixed-regexp", no_argument, NULL, 'F'}, 13053477Sobrien {"fixed-strings", no_argument, NULL, 'F'}, 13153477Sobrien {"help", no_argument, &show_help, 1}, 132131557Stjr {"include", required_argument, NULL, INCLUDE_OPTION}, 13353477Sobrien {"ignore-case", no_argument, NULL, 'i'}, 134131557Stjr {"label", required_argument, NULL, LABEL_OPTION}, 135131557Stjr {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION}, 13653477Sobrien {"line-number", no_argument, NULL, 'n'}, 13753477Sobrien {"line-regexp", no_argument, NULL, 'x'}, 138131557Stjr {"max-count", required_argument, NULL, 'm'}, 13955379Sobrien {"mmap", no_argument, &mmap_option, 1}, 14053477Sobrien {"no-filename", no_argument, NULL, 'h'}, 14153477Sobrien {"no-messages", no_argument, NULL, 's'}, 142103372Sobrien {"bz2decompress", no_argument, NULL, 'J'}, 14355379Sobrien#if HAVE_LIBZ > 0 14455404Sru {"decompress", no_argument, NULL, 'Z'}, 14555404Sru {"null", no_argument, &filename_mask, 0}, 14655379Sobrien#else 14755379Sobrien {"null", no_argument, NULL, 'Z'}, 14855379Sobrien#endif 14955379Sobrien {"null-data", no_argument, NULL, 'z'}, 150131557Stjr {"only-matching", no_argument, NULL, 'o'}, 151131557Stjr {"perl-regexp", no_argument, NULL, 'P'}, 15253477Sobrien {"quiet", no_argument, NULL, 'q'}, 15353477Sobrien {"recursive", no_argument, NULL, 'r'}, 154131557Stjr {"recursive", no_argument, NULL, 'R'}, 15553477Sobrien {"regexp", required_argument, NULL, 'e'}, 15655379Sobrien {"invert-match", no_argument, NULL, 'v'}, 15753477Sobrien {"silent", no_argument, NULL, 'q'}, 15853477Sobrien {"text", no_argument, NULL, 'a'}, 15953477Sobrien {"binary", no_argument, NULL, 'U'}, 16053477Sobrien {"unix-byte-offsets", no_argument, NULL, 'u'}, 16153477Sobrien {"version", no_argument, NULL, 'V'}, 16253477Sobrien {"with-filename", no_argument, NULL, 'H'}, 16353477Sobrien {"word-regexp", no_argument, NULL, 'w'}, 16453477Sobrien {0, 0, 0, 0} 16553477Sobrien}; 16653451Speter 16753451Speter/* Define flags declared in grep.h. */ 16853451Speterint match_icase; 16953451Speterint match_words; 17053451Speterint match_lines; 17155379Sobrienunsigned char eolbyte; 17253451Speter 17353451Speter/* For error messages. */ 174131557Stjr/* The name the program was run with, stripped of any leading path. */ 175131557Stjrchar *program_name; 17653477Sobrienstatic char const *filename; 17753451Speterstatic int errseen; 17853451Speter 17953477Sobrien/* How to handle directories. */ 18053477Sobrienstatic enum 18153477Sobrien { 18253477Sobrien READ_DIRECTORIES, 18353477Sobrien RECURSE_DIRECTORIES, 18453477Sobrien SKIP_DIRECTORIES 185131557Stjr } directories = READ_DIRECTORIES; 18653477Sobrien 187131557Stjr/* How to handle devices. */ 188131557Stjrstatic enum 189131557Stjr { 190131557Stjr READ_DEVICES, 191131557Stjr SKIP_DEVICES 192131557Stjr } devices = READ_DEVICES; 193131557Stjr 194131557Stjrstatic int grepdir PARAMS ((char const *, struct stats const *)); 195131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 19653477Sobrienstatic inline int undossify_input PARAMS ((register char *, size_t)); 19753477Sobrien#endif 19853477Sobrien 19953477Sobrien/* Functions we'll use to search. */ 200131557Stjrstatic void (*compile) PARAMS ((char const *, size_t)); 201146199Stjrstatic size_t (*execute) PARAMS ((char const *, size_t, size_t *, int)); 20253477Sobrien 203131557Stjr/* Like error, but suppress the diagnostic if requested. */ 20453451Speterstatic void 205131557Stjrsuppressible_error (char const *mesg, int errnum) 20653451Speter{ 207131557Stjr if (! suppress_errors) 208131557Stjr error (0, errnum, "%s", mesg); 20953451Speter errseen = 1; 21053451Speter} 21153451Speter 21253477Sobrien/* Convert STR to a positive integer, storing the result in *OUT. 213131557Stjr STR must be a valid context length argument; report an error if it 214131557Stjr isn't. */ 215131557Stjrstatic void 216131557Stjrcontext_length_arg (char const *str, int *out) 21753477Sobrien{ 218131557Stjr uintmax_t value; 219131557Stjr if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK 220131557Stjr && 0 <= (*out = value) 221131557Stjr && *out == value)) 222131557Stjr { 223131557Stjr error (2, 0, "%s: %s\n", str, _("invalid context length argument")); 224131557Stjr } 22553477Sobrien} 22653477Sobrien 22753477Sobrien 22853451Speter/* Hairy buffering mechanism for grep. The intent is to keep 22953451Speter all reads aligned on a page boundary and multiples of the 230131557Stjr page size, unless a read yields a partial page. */ 23153451Speter 23253451Speterstatic char *buffer; /* Base of buffer. */ 233131557Stjrstatic size_t bufalloc; /* Allocated buffer size, counting slop. */ 234131557Stjr#define INITIAL_BUFSIZE 32768 /* Initial buffer size, not counting slop. */ 23553451Speterstatic int bufdesc; /* File descriptor. */ 23653451Speterstatic char *bufbeg; /* Beginning of user-visible stuff. */ 23753451Speterstatic char *buflim; /* Limit of user-visible stuff. */ 23853477Sobrienstatic size_t pagesize; /* alignment of memory pages */ 23955379Sobrienstatic off_t bufoffset; /* Read offset; defined on regular files. */ 240131557Stjrstatic off_t after_last_match; /* Pointer after last matching line that 241131557Stjr would have been output if we were 242131557Stjr outputting characters. */ 24353451Speter 24453477Sobrien#if defined(HAVE_MMAP) 24555379Sobrienstatic int bufmapped; /* True if buffer is memory-mapped. */ 24653477Sobrienstatic off_t initial_bufoffset; /* Initial value of bufoffset. */ 247131557Stjr#else 248131557Stjr# define bufmapped 0 24953451Speter#endif 25053451Speter 251103372Sobrien#include <bzlib.h> 252103372Sobrienstatic BZFILE* bzbufdesc; /* libbz2 file handle. */ 253103372Sobrienstatic int BZflag; /* uncompress before searching. */ 25453451Speter#if HAVE_LIBZ > 0 25553451Speter#include <zlib.h> 25653477Sobrienstatic gzFile gzbufdesc; /* zlib file descriptor. */ 25753477Sobrienstatic int Zflag; /* uncompress before searching. */ 25853451Speter#endif 25953451Speter 26053477Sobrien/* Return VAL aligned to the next multiple of ALIGNMENT. VAL can be 26153477Sobrien an integer or a pointer. Both args must be free of side effects. */ 26253477Sobrien#define ALIGN_TO(val, alignment) \ 26353477Sobrien ((size_t) (val) % (alignment) == 0 \ 26453477Sobrien ? (val) \ 26553477Sobrien : (val) + ((alignment) - (size_t) (val) % (alignment))) 26653477Sobrien 26753477Sobrien/* Reset the buffer for a new file, returning zero if we should skip it. 26853477Sobrien Initialize on the first time through. */ 26953477Sobrienstatic int 27056920Srureset (int fd, char const *file, struct stats *stats) 27153451Speter{ 272131557Stjr if (! pagesize) 27353451Speter { 27453477Sobrien pagesize = getpagesize (); 275131557Stjr if (pagesize == 0 || 2 * pagesize + 1 <= pagesize) 27653477Sobrien abort (); 277131557Stjr bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1; 278131557Stjr buffer = xmalloc (bufalloc); 27953451Speter } 280103372Sobrien if (BZflag) 281103372Sobrien { 282103372Sobrien bzbufdesc = BZ2_bzdopen(fd, "r"); 283103372Sobrien if (bzbufdesc == NULL) 284131557Stjr error(2, 0, _("memory exhausted")); 285103372Sobrien } 28653451Speter#if HAVE_LIBZ > 0 28755379Sobrien if (Zflag) 28855379Sobrien { 28953451Speter gzbufdesc = gzdopen(fd, "r"); 29053477Sobrien if (gzbufdesc == NULL) 291131557Stjr error(2, 0, _("memory exhausted")); 29255379Sobrien } 29353451Speter#endif 29455379Sobrien 295131557Stjr bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize); 296131557Stjr bufbeg[-1] = eolbyte; 29753477Sobrien bufdesc = fd; 29853477Sobrien 29955379Sobrien if (fstat (fd, &stats->stat) != 0) 30055379Sobrien { 301131557Stjr error (0, errno, "fstat"); 30255379Sobrien return 0; 30355379Sobrien } 304254093Sache if (fd != STDIN_FILENO) { 305254093Sache if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode)) 306254093Sache return 0; 307131557Stjr#ifndef DJGPP 308254093Sache if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode) || S_ISFIFO(stats->stat.st_mode))) 309131557Stjr#else 310254093Sache if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode))) 311131557Stjr#endif 312254093Sache return 0; 313254093Sache } 31453477Sobrien if ( 315103372Sobrien BZflag || 31653451Speter#if HAVE_LIBZ > 0 31753477Sobrien Zflag || 31853451Speter#endif 31955379Sobrien S_ISREG (stats->stat.st_mode)) 32055379Sobrien { 32155379Sobrien if (file) 32255379Sobrien bufoffset = 0; 32355379Sobrien else 32455379Sobrien { 32555379Sobrien bufoffset = lseek (fd, 0, SEEK_CUR); 32655379Sobrien if (bufoffset < 0) 32755379Sobrien { 328131557Stjr error (0, errno, "lseek"); 32955379Sobrien return 0; 33055379Sobrien } 33155379Sobrien } 332131557Stjr#if defined(HAVE_MMAP) 33355379Sobrien initial_bufoffset = bufoffset; 33455379Sobrien bufmapped = mmap_option && bufoffset % pagesize == 0; 33555379Sobrien#endif 33655379Sobrien } 33753451Speter else 33853451Speter { 339131557Stjr#if defined(HAVE_MMAP) 34055379Sobrien bufmapped = 0; 34155379Sobrien#endif 34253451Speter } 34353477Sobrien return 1; 34453451Speter} 34553451Speter 34653451Speter/* Read new stuff into the buffer, saving the specified 34753451Speter amount of old stuff. When we're done, 'bufbeg' points 34853451Speter to the beginning of the buffer contents, and 'buflim' 34955379Sobrien points just after the end. Return zero if there's an error. */ 35053451Speterstatic int 351131557Stjrfillbuf (size_t save, struct stats const *stats) 35253451Speter{ 35355379Sobrien size_t fillsize = 0; 35455379Sobrien int cc = 1; 355131557Stjr char *readbuf; 35655379Sobrien size_t readsize; 35753451Speter 358131557Stjr /* Offset from start of buffer to start of old stuff 35955379Sobrien that we want to save. */ 360131557Stjr size_t saved_offset = buflim - save - buffer; 36155379Sobrien 362131557Stjr if (pagesize <= buffer + bufalloc - buflim) 36353451Speter { 364131557Stjr readbuf = buflim; 365131557Stjr bufbeg = buflim - save; 366131557Stjr } 367131557Stjr else 368131557Stjr { 369131557Stjr size_t minsize = save + pagesize; 370131557Stjr size_t newsize; 37155379Sobrien size_t newalloc; 372131557Stjr char *newbuf; 37353477Sobrien 374131557Stjr /* Grow newsize until it is at least as great as minsize. */ 375131557Stjr for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2) 376131557Stjr if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2) 377131557Stjr xalloc_die (); 378131557Stjr 379131557Stjr /* Try not to allocate more memory than the file size indicates, 380131557Stjr as that might cause unnecessary memory exhaustion if the file 381131557Stjr is large. However, do not use the original file size as a 382131557Stjr heuristic if we've already read past the file end, as most 383131557Stjr likely the file is growing. */ 38455379Sobrien if (S_ISREG (stats->stat.st_mode)) 38555379Sobrien { 38655379Sobrien off_t to_be_read = stats->stat.st_size - bufoffset; 387131557Stjr off_t maxsize_off = save + to_be_read; 388131557Stjr if (0 <= to_be_read && to_be_read <= maxsize_off 389131557Stjr && maxsize_off == (size_t) maxsize_off 390131557Stjr && minsize <= (size_t) maxsize_off 391131557Stjr && (size_t) maxsize_off < newsize) 392131557Stjr newsize = maxsize_off; 39355379Sobrien } 39455379Sobrien 395131557Stjr /* Add enough room so that the buffer is aligned and has room 396131557Stjr for byte sentinels fore and aft. */ 397131557Stjr newalloc = newsize + pagesize + 1; 39855379Sobrien 399131557Stjr newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer; 400131557Stjr readbuf = ALIGN_TO (newbuf + 1 + save, pagesize); 401131557Stjr bufbeg = readbuf - save; 402131557Stjr memmove (bufbeg, buffer + saved_offset, save); 403131557Stjr bufbeg[-1] = eolbyte; 404131557Stjr if (newbuf != buffer) 40555379Sobrien { 406131557Stjr free (buffer); 407131557Stjr buffer = newbuf; 40855379Sobrien } 40953451Speter } 41053451Speter 411131557Stjr readsize = buffer + bufalloc - readbuf; 412131557Stjr readsize -= readsize % pagesize; 41355379Sobrien 41453477Sobrien#if defined(HAVE_MMAP) 41555379Sobrien if (bufmapped) 41653451Speter { 41755379Sobrien size_t mmapsize = readsize; 41855379Sobrien 41955379Sobrien /* Don't mmap past the end of the file; some hosts don't allow this. 42055379Sobrien Use `read' on the last page. */ 42155379Sobrien if (stats->stat.st_size - bufoffset < mmapsize) 42253451Speter { 42355379Sobrien mmapsize = stats->stat.st_size - bufoffset; 42455379Sobrien mmapsize -= mmapsize % pagesize; 42553451Speter } 42655379Sobrien 42755379Sobrien if (mmapsize 428131557Stjr && (mmap ((caddr_t) readbuf, mmapsize, 42955379Sobrien PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 43055379Sobrien bufdesc, bufoffset) 43155379Sobrien != (caddr_t) -1)) 43253451Speter { 43355379Sobrien /* Do not bother to use madvise with MADV_SEQUENTIAL or 43455379Sobrien MADV_WILLNEED on the mmapped memory. One might think it 43555379Sobrien would help, but it slows us down about 30% on SunOS 4.1. */ 43655379Sobrien fillsize = mmapsize; 43755379Sobrien } 43855379Sobrien else 43955379Sobrien { 44055379Sobrien /* Stop using mmap on this file. Synchronize the file 44155379Sobrien offset. Do not warn about mmap failures. On some hosts 44255379Sobrien (e.g. Solaris 2.5) mmap can fail merely because some 44355379Sobrien other process has an advisory read lock on the file. 44455379Sobrien There's no point alarming the user about this misfeature. */ 44553451Speter bufmapped = 0; 44655379Sobrien if (bufoffset != initial_bufoffset 44755379Sobrien && lseek (bufdesc, bufoffset, SEEK_SET) < 0) 44855379Sobrien { 449131557Stjr error (0, errno, "lseek"); 45055379Sobrien cc = 0; 45155379Sobrien } 45253451Speter } 45355379Sobrien } 45455379Sobrien#endif /*HAVE_MMAP*/ 45555379Sobrien 45655379Sobrien if (! fillsize) 45755379Sobrien { 45855379Sobrien ssize_t bytesread; 45955379Sobrien do 460104555Sobrien if (BZflag && bzbufdesc) 461103372Sobrien { 462104555Sobrien int bzerr; 463131557Stjr bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize); 464104555Sobrien 465104555Sobrien switch (bzerr) 466104555Sobrien { 467104555Sobrien case BZ_OK: 468104555Sobrien case BZ_STREAM_END: 469104555Sobrien /* ok */ 470104555Sobrien break; 471104555Sobrien case BZ_DATA_ERROR_MAGIC: 472104555Sobrien BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL; 473104555Sobrien lseek (bufdesc, 0, SEEK_SET); 474131557Stjr bytesread = read (bufdesc, readbuf, readsize); 475104555Sobrien break; 476104555Sobrien default: 477104555Sobrien bytesread = 0; 478104555Sobrien break; 479104555Sobrien } 480103372Sobrien } 481103372Sobrien else 48253451Speter#if HAVE_LIBZ > 0 48355379Sobrien if (Zflag) 484131557Stjr bytesread = gzread (gzbufdesc, readbuf, readsize); 48555379Sobrien else 48655379Sobrien#endif 487131557Stjr bytesread = read (bufdesc, readbuf, readsize); 48855379Sobrien while (bytesread < 0 && errno == EINTR); 48955379Sobrien if (bytesread < 0) 49055379Sobrien cc = 0; 49153477Sobrien else 49255379Sobrien fillsize = bytesread; 49353451Speter } 49455379Sobrien 49555379Sobrien bufoffset += fillsize; 496131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 49755379Sobrien if (fillsize) 498131557Stjr fillsize = undossify_input (readbuf, fillsize); 49953451Speter#endif 500131557Stjr buflim = readbuf + fillsize; 50153451Speter return cc; 50253451Speter} 50353451Speter 50453451Speter/* Flags controlling the style of output. */ 50556233Srustatic enum 506131557Stjr{ 507131557Stjr BINARY_BINARY_FILES, 508131557Stjr TEXT_BINARY_FILES, 509131557Stjr WITHOUT_MATCH_BINARY_FILES 510131557Stjr} binary_files; /* How to handle binary files. */ 511131557Stjr 512131557Stjrstatic int filename_mask; /* If zero, output nulls after filenames. */ 51353451Speterstatic int out_quiet; /* Suppress all normal output. */ 51453451Speterstatic int out_invert; /* Print nonmatching stuff. */ 51553451Speterstatic int out_file; /* Print filenames. */ 51653451Speterstatic int out_line; /* Print line numbers. */ 51753451Speterstatic int out_byte; /* Print byte offsets. */ 51853451Speterstatic int out_before; /* Lines of leading context. */ 51953451Speterstatic int out_after; /* Lines of trailing context. */ 52053477Sobrienstatic int count_matches; /* Count matching lines. */ 52153477Sobrienstatic int list_files; /* List matching files. */ 52253477Sobrienstatic int no_filenames; /* Suppress file names. */ 523131557Stjrstatic off_t max_count; /* Stop after outputting this many 524131557Stjr lines from an input file. */ 525131557Stjrstatic int line_buffered; /* If nonzero, use line buffering, i.e. 526131557Stjr fflush everyline out. */ 527131557Stjrstatic char *label = NULL; /* Fake filename for stdin */ 52853451Speter 529131557Stjr 53053451Speter/* Internal variables to keep track of byte count, context, etc. */ 531131557Stjrstatic uintmax_t totalcc; /* Total character count before bufbeg. */ 532131557Stjrstatic char const *lastnl; /* Pointer after last newline counted. */ 533131557Stjrstatic char const *lastout; /* Pointer after last character output; 53453451Speter NULL if no character has been output 53553451Speter or if it's conceptually before bufbeg. */ 536131557Stjrstatic uintmax_t totalnl; /* Total newline count before lastnl. */ 537131557Stjrstatic off_t outleft; /* Maximum number of lines to be output. */ 538131557Stjrstatic int pending; /* Pending lines of output. 539131557Stjr Always kept 0 if out_quiet is true. */ 540131557Stjrstatic int done_on_match; /* Stop scanning file on first match. */ 541131557Stjrstatic int exit_on_match; /* Exit on first match. */ 54253451Speter 543131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 54453477Sobrien# include "dosbuf.c" 54553477Sobrien#endif 54653477Sobrien 547131557Stjr/* Add two numbers that count input bytes or lines, and report an 548131557Stjr error if the addition overflows. */ 549131557Stjrstatic uintmax_t 550131557Stjradd_count (uintmax_t a, uintmax_t b) 551131557Stjr{ 552131557Stjr uintmax_t sum = a + b; 553131557Stjr if (sum < a) 554131557Stjr error (2, 0, _("input is too large to count")); 555131557Stjr return sum; 556131557Stjr} 557131557Stjr 55853451Speterstatic void 559131557Stjrnlscan (char const *lim) 56053451Speter{ 561131557Stjr size_t newlines = 0; 562131557Stjr char const *beg; 563131557Stjr for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++) 564131557Stjr newlines++; 565131557Stjr totalnl = add_count (totalnl, newlines); 56655379Sobrien lastnl = lim; 56753451Speter} 56853451Speter 569131557Stjr/* Print a byte offset, followed by a character separator. */ 57053451Speterstatic void 571131557Stjrprint_offset_sep (uintmax_t pos, char sep) 57253477Sobrien{ 573131557Stjr /* Do not rely on printf to print pos, since uintmax_t may be longer 574131557Stjr than long, and long long is not portable. */ 57553477Sobrien 57653477Sobrien char buf[sizeof pos * CHAR_BIT]; 57753477Sobrien char *p = buf + sizeof buf - 1; 57853477Sobrien *p = sep; 57953477Sobrien 58053477Sobrien do 58153477Sobrien *--p = '0' + pos % 10; 58253477Sobrien while ((pos /= 10) != 0); 58353477Sobrien 58453477Sobrien fwrite (p, 1, buf + sizeof buf - p, stdout); 58553477Sobrien} 58653477Sobrien 58753477Sobrienstatic void 588146199Stjrprline (char const *beg, char const *lim, int sep) 58953451Speter{ 59053451Speter if (out_file) 59155379Sobrien printf ("%s%c", filename, sep & filename_mask); 59253451Speter if (out_line) 59353451Speter { 59453477Sobrien nlscan (beg); 595131557Stjr totalnl = add_count (totalnl, 1); 596131557Stjr print_offset_sep (totalnl, sep); 59753451Speter lastnl = lim; 59853451Speter } 59953451Speter if (out_byte) 60053477Sobrien { 601131557Stjr uintmax_t pos = add_count (totalcc, beg - bufbeg); 602131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 60353477Sobrien pos = dossified_pos (pos); 60453477Sobrien#endif 60553477Sobrien print_offset_sep (pos, sep); 60653477Sobrien } 607131557Stjr if (only_matching) 608131557Stjr { 609131557Stjr size_t match_size; 610131557Stjr size_t match_offset; 611146199Stjr while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1)) 612131557Stjr != (size_t) -1) 613131557Stjr { 614131557Stjr char const *b = beg + match_offset; 615131557Stjr if (b == lim) 616131557Stjr break; 617131557Stjr if (match_size == 0) 618131557Stjr break; 619131557Stjr if(color_option) 620131557Stjr printf("\33[%sm", grep_color); 621131557Stjr fwrite(b, sizeof (char), match_size, stdout); 622131557Stjr if(color_option) 623131557Stjr fputs("\33[00m", stdout); 624131557Stjr fputs("\n", stdout); 625131557Stjr beg = b + match_size; 626131557Stjr } 627131557Stjr lastout = lim; 628131557Stjr if(line_buffered) 629131557Stjr fflush(stdout); 630131557Stjr return; 631131557Stjr } 632131557Stjr if (color_option) 633131557Stjr { 634131557Stjr size_t match_size; 635131557Stjr size_t match_offset; 636146199Stjr while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1)) 637131557Stjr != (size_t) -1) 638131557Stjr { 639131557Stjr char const *b = beg + match_offset; 640131557Stjr /* Avoid matching the empty line at the end of the buffer. */ 641131557Stjr if (b == lim) 642131557Stjr break; 643131557Stjr /* Avoid hanging on grep --color "" foo */ 644131557Stjr if (match_size == 0) 645131557Stjr break; 646131557Stjr fwrite (beg, sizeof (char), match_offset, stdout); 647131557Stjr printf ("\33[%sm", grep_color); 648131557Stjr fwrite (b, sizeof (char), match_size, stdout); 649131557Stjr fputs ("\33[00m", stdout); 650131557Stjr beg = b + match_size; 651131557Stjr } 652146203Stjr fputs ("\33[K", stdout); 653131557Stjr } 65453477Sobrien fwrite (beg, 1, lim - beg, stdout); 65553477Sobrien if (ferror (stdout)) 656131557Stjr error (0, errno, _("writing output")); 65753451Speter lastout = lim; 658131557Stjr if (line_buffered) 659131557Stjr fflush (stdout); 66053451Speter} 66153451Speter 662131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends 663131557Stjr at the next matching line when OUTLEFT is 0. */ 66453451Speterstatic void 665146199Stjrprpending (char const *lim) 66653451Speter{ 66753451Speter if (!lastout) 66853451Speter lastout = bufbeg; 66953451Speter while (pending > 0 && lastout < lim) 67053451Speter { 671131557Stjr char const *nl = memchr (lastout, eolbyte, lim - lastout); 672131557Stjr size_t match_size; 67353451Speter --pending; 674131557Stjr if (outleft 675146199Stjr || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1) 676131557Stjr == !out_invert)) 677146199Stjr prline (lastout, nl + 1, '-'); 67853451Speter else 679131557Stjr pending = 0; 68053451Speter } 68153451Speter} 68253451Speter 68353451Speter/* Print the lines between BEG and LIM. Deal with context crap. 684131557Stjr If NLINESP is non-null, store a count of lines between BEG and LIM. */ 68553451Speterstatic void 686146199Stjrprtext (char const *beg, char const *lim, int *nlinesp) 68753451Speter{ 68853451Speter static int used; /* avoid printing "--" before any output */ 689131557Stjr char const *bp, *p; 69055379Sobrien char eol = eolbyte; 69153451Speter int i, n; 69253451Speter 69353451Speter if (!out_quiet && pending > 0) 694146199Stjr prpending (beg); 69553451Speter 69653451Speter p = beg; 69753451Speter 69853451Speter if (!out_quiet) 69953451Speter { 70053451Speter /* Deal with leading context crap. */ 70153451Speter 70253451Speter bp = lastout ? lastout : bufbeg; 70353451Speter for (i = 0; i < out_before; ++i) 70453451Speter if (p > bp) 70553451Speter do 70653451Speter --p; 707131557Stjr while (p[-1] != eol); 70853451Speter 70953451Speter /* We only print the "--" separator if our output is 71053451Speter discontiguous from the last output in the file. */ 71153451Speter if ((out_before || out_after) && used && p != lastout) 71253477Sobrien puts ("--"); 71353451Speter 71453451Speter while (p < beg) 71553451Speter { 716131557Stjr char const *nl = memchr (p, eol, beg - p); 717131557Stjr nl++; 718146199Stjr prline (p, nl, '-'); 719131557Stjr p = nl; 72053451Speter } 72153451Speter } 72253451Speter 72353451Speter if (nlinesp) 72453451Speter { 72553451Speter /* Caller wants a line count. */ 726131557Stjr for (n = 0; p < lim && n < outleft; n++) 72753451Speter { 728131557Stjr char const *nl = memchr (p, eol, lim - p); 729131557Stjr nl++; 73053451Speter if (!out_quiet) 731146199Stjr prline (p, nl, ':'); 73253451Speter p = nl; 73353451Speter } 73453451Speter *nlinesp = n; 735131557Stjr 736131557Stjr /* relying on it that this function is never called when outleft = 0. */ 737131557Stjr after_last_match = bufoffset - (buflim - p); 73853451Speter } 73953451Speter else 74053451Speter if (!out_quiet) 741146199Stjr prline (beg, lim, ':'); 74253451Speter 74355379Sobrien pending = out_quiet ? 0 : out_after; 74453451Speter used = 1; 74553451Speter} 74653451Speter 74753451Speter/* Scan the specified portion of the buffer, matching lines (or 74853451Speter between matching lines if OUT_INVERT is true). Return a count of 74953451Speter lines printed. */ 75053451Speterstatic int 751146199Stjrgrepbuf (char const *beg, char const *lim) 75253451Speter{ 75353451Speter int nlines, n; 754131557Stjr register char const *p; 755131557Stjr size_t match_offset; 756131557Stjr size_t match_size; 75753451Speter 75853451Speter nlines = 0; 75953451Speter p = beg; 760146199Stjr while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1) 76153451Speter { 762131557Stjr char const *b = p + match_offset; 763131557Stjr char const *endp = b + match_size; 76453451Speter /* Avoid matching the empty line at the end of the buffer. */ 765131557Stjr if (b == lim) 76653451Speter break; 76753451Speter if (!out_invert) 76853451Speter { 769146199Stjr prtext (b, endp, (int *) 0); 770131557Stjr nlines++; 771131557Stjr outleft--; 772131557Stjr if (!outleft || done_on_match) 773131557Stjr { 774131557Stjr if (exit_on_match) 775131557Stjr exit (0); 776131557Stjr after_last_match = bufoffset - (buflim - endp); 777131557Stjr return nlines; 778131557Stjr } 77953451Speter } 78053451Speter else if (p < b) 78153451Speter { 782146199Stjr prtext (p, b, &n); 78353451Speter nlines += n; 784131557Stjr outleft -= n; 785131557Stjr if (!outleft) 786131557Stjr return nlines; 78753451Speter } 78853451Speter p = endp; 78953451Speter } 79053451Speter if (out_invert && p < lim) 79153451Speter { 792146199Stjr prtext (p, lim, &n); 79353451Speter nlines += n; 794131557Stjr outleft -= n; 79553451Speter } 79653451Speter return nlines; 79753451Speter} 79853451Speter 79953477Sobrien/* Search a given file. Normally, return a count of lines printed; 80053477Sobrien but if the file is a directory and we search it recursively, then 80153477Sobrien return -2 if there was a match, and -1 otherwise. */ 80253451Speterstatic int 80356920Srugrep (int fd, char const *file, struct stats *stats) 80453451Speter{ 80553451Speter int nlines, i; 80653477Sobrien int not_text; 80753451Speter size_t residue, save; 808131557Stjr char oldc; 809131557Stjr char *beg; 810131557Stjr char *lim; 81155379Sobrien char eol = eolbyte; 81253451Speter 81353477Sobrien if (!reset (fd, file, stats)) 81453477Sobrien return 0; 81553451Speter 81653477Sobrien if (file && directories == RECURSE_DIRECTORIES 81753477Sobrien && S_ISDIR (stats->stat.st_mode)) 81853477Sobrien { 81953477Sobrien /* Close fd now, so that we don't open a lot of file descriptors 82053477Sobrien when we recurse deeply. */ 821104555Sobrien if (BZflag && bzbufdesc) 822103372Sobrien BZ2_bzclose(bzbufdesc); 823103372Sobrien else 82453477Sobrien#if HAVE_LIBZ > 0 82553477Sobrien if (Zflag) 82653477Sobrien gzclose(gzbufdesc); 82753477Sobrien else 82853477Sobrien#endif 82953477Sobrien if (close (fd) != 0) 830131557Stjr error (0, errno, "%s", file); 83153477Sobrien return grepdir (file, stats) - 2; 83253477Sobrien } 83353477Sobrien 83453451Speter totalcc = 0; 83553451Speter lastout = 0; 83653451Speter totalnl = 0; 837131557Stjr outleft = max_count; 838131557Stjr after_last_match = 0; 83953451Speter pending = 0; 84053451Speter 84153451Speter nlines = 0; 84253451Speter residue = 0; 84353451Speter save = 0; 84453451Speter 84555379Sobrien if (! fillbuf (save, stats)) 84653451Speter { 847131557Stjr if (! is_EISDIR (errno, file)) 848131557Stjr suppressible_error (filename, errno); 84956233Sru return 0; 85053477Sobrien } 85153451Speter 85256233Sru not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet) 85356233Sru || binary_files == WITHOUT_MATCH_BINARY_FILES) 85455379Sobrien && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg)); 85556233Sru if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES) 85656233Sru return 0; 85753477Sobrien done_on_match += not_text; 85853477Sobrien out_quiet += not_text; 85953451Speter 86053477Sobrien for (;;) 86153477Sobrien { 86253451Speter lastnl = bufbeg; 86353451Speter if (lastout) 86453451Speter lastout = bufbeg; 865131557Stjr 866131557Stjr beg = bufbeg + save; 867131557Stjr 868131557Stjr /* no more data to scan (eof) except for maybe a residue -> break */ 869131557Stjr if (beg == buflim) 87053451Speter break; 871131557Stjr 872131557Stjr /* Determine new residue (the length of an incomplete line at the end of 873131557Stjr the buffer, 0 means there is no incomplete last line). */ 874131557Stjr oldc = beg[-1]; 875131557Stjr beg[-1] = eol; 876131557Stjr for (lim = buflim; lim[-1] != eol; lim--) 877131557Stjr continue; 878131557Stjr beg[-1] = oldc; 879131557Stjr if (lim == beg) 880131557Stjr lim = beg - residue; 881131557Stjr beg -= residue; 88253451Speter residue = buflim - lim; 883131557Stjr 88453451Speter if (beg < lim) 88553451Speter { 886131557Stjr if (outleft) 887146199Stjr nlines += grepbuf (beg, lim); 88853451Speter if (pending) 889146199Stjr prpending (lim); 890131557Stjr if((!outleft && !pending) || (nlines && done_on_match && !out_invert)) 89153477Sobrien goto finish_grep; 89253451Speter } 893131557Stjr 894131557Stjr /* The last OUT_BEFORE lines at the end of the buffer will be needed as 895131557Stjr leading context if there is a matching line at the begin of the 896131557Stjr next data. Make beg point to their begin. */ 89753451Speter i = 0; 89853451Speter beg = lim; 89953451Speter while (i < out_before && beg > bufbeg && beg != lastout) 90053451Speter { 90153451Speter ++i; 90253451Speter do 90353451Speter --beg; 904131557Stjr while (beg[-1] != eol); 90553451Speter } 906131557Stjr 907131557Stjr /* detect if leading context is discontinuous from last printed line. */ 90853451Speter if (beg != lastout) 90953451Speter lastout = 0; 910131557Stjr 911131557Stjr /* Handle some details and read more data to scan. */ 91253451Speter save = residue + lim - beg; 913131557Stjr if (out_byte) 914131557Stjr totalcc = add_count (totalcc, buflim - bufbeg - save); 91553451Speter if (out_line) 91653477Sobrien nlscan (beg); 91755379Sobrien if (! fillbuf (save, stats)) 91853477Sobrien { 919131557Stjr if (! is_EISDIR (errno, file)) 920131557Stjr suppressible_error (filename, errno); 92153477Sobrien goto finish_grep; 92253477Sobrien } 92353451Speter } 92453451Speter if (residue) 92553451Speter { 92656920Sru *buflim++ = eol; 927131557Stjr if (outleft) 928146199Stjr nlines += grepbuf (bufbeg + save - residue, buflim); 92953451Speter if (pending) 930146199Stjr prpending (buflim); 93153451Speter } 93253477Sobrien 93353477Sobrien finish_grep: 93453477Sobrien done_on_match -= not_text; 93553477Sobrien out_quiet -= not_text; 93653477Sobrien if ((not_text & ~out_quiet) && nlines != 0) 93753477Sobrien printf (_("Binary file %s matches\n"), filename); 93853451Speter return nlines; 93953451Speter} 94053451Speter 94153477Sobrienstatic int 94256920Srugrepfile (char const *file, struct stats *stats) 94353477Sobrien{ 94453477Sobrien int desc; 94553477Sobrien int count; 94653477Sobrien int status; 947245761Sdavidxu int flags; 94853477Sobrien 94953477Sobrien if (! file) 95053477Sobrien { 95153477Sobrien desc = 0; 952131557Stjr filename = label ? label : _("(standard input)"); 95353477Sobrien } 95453477Sobrien else 95553477Sobrien { 956245761Sdavidxu while ((desc = open (file, O_RDONLY | O_NONBLOCK)) < 0 && errno == EINTR) 95755379Sobrien continue; 95853477Sobrien 95953477Sobrien if (desc < 0) 96053477Sobrien { 96153477Sobrien int e = errno; 962131557Stjr 96353477Sobrien if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES) 96453477Sobrien { 96553477Sobrien if (stat (file, &stats->stat) != 0) 96653477Sobrien { 967131557Stjr error (0, errno, "%s", file); 96853477Sobrien return 1; 96953477Sobrien } 97053477Sobrien 97153477Sobrien return grepdir (file, stats); 97253477Sobrien } 973131557Stjr 97453477Sobrien if (!suppress_errors) 97553477Sobrien { 97653477Sobrien if (directories == SKIP_DIRECTORIES) 97753477Sobrien switch (e) 97853477Sobrien { 979131557Stjr#if defined(EISDIR) 98053477Sobrien case EISDIR: 98153477Sobrien return 1; 98253451Speter#endif 98353477Sobrien case EACCES: 98453477Sobrien /* When skipping directories, don't worry about 98553477Sobrien directories that can't be opened. */ 986131557Stjr if (isdir (file)) 98753477Sobrien return 1; 98853477Sobrien break; 98953477Sobrien } 99053477Sobrien } 99153477Sobrien 992131557Stjr suppressible_error (file, e); 99353477Sobrien return 1; 99453477Sobrien } 99553477Sobrien 996245761Sdavidxu flags = fcntl(desc, F_GETFL); 997245761Sdavidxu flags &= ~O_NONBLOCK; 998245761Sdavidxu fcntl(desc, F_SETFL, flags); 99953477Sobrien filename = file; 100053477Sobrien } 100153477Sobrien 1002131557Stjr#if defined(SET_BINARY) 100353477Sobrien /* Set input to binary mode. Pipes are simulated with files 100453477Sobrien on DOS, so this includes the case of "foo | grep bar". */ 100553477Sobrien if (!isatty (desc)) 100653477Sobrien SET_BINARY (desc); 100753477Sobrien#endif 100853477Sobrien 100953477Sobrien count = grep (desc, file, stats); 101053477Sobrien if (count < 0) 101153477Sobrien status = count + 2; 101253477Sobrien else 101353477Sobrien { 101453477Sobrien if (count_matches) 101553477Sobrien { 101653477Sobrien if (out_file) 101755379Sobrien printf ("%s%c", filename, ':' & filename_mask); 101853477Sobrien printf ("%d\n", count); 101953477Sobrien } 102053477Sobrien 102155379Sobrien status = !count; 102255379Sobrien if (list_files == 1 - 2 * status) 102355379Sobrien printf ("%s%c", filename, '\n' & filename_mask); 102453477Sobrien 1025104555Sobrien if (BZflag && bzbufdesc) 1026103372Sobrien BZ2_bzclose(bzbufdesc); 1027103372Sobrien else 102853451Speter#if HAVE_LIBZ > 0 102953477Sobrien if (Zflag) 103053477Sobrien gzclose(gzbufdesc); 103153477Sobrien else 103253451Speter#endif 1033131557Stjr if (! file) 1034131557Stjr { 1035131557Stjr off_t required_offset = outleft ? bufoffset : after_last_match; 1036131557Stjr if ((bufmapped || required_offset != bufoffset) 1037131557Stjr && lseek (desc, required_offset, SEEK_SET) < 0 1038131557Stjr && S_ISREG (stats->stat.st_mode)) 1039131557Stjr error (0, errno, "%s", filename); 1040131557Stjr } 1041131557Stjr else 104255379Sobrien while (close (desc) != 0) 104355379Sobrien if (errno != EINTR) 104455379Sobrien { 1045131557Stjr error (0, errno, "%s", file); 104655379Sobrien break; 104755379Sobrien } 104853477Sobrien } 104953451Speter 105053477Sobrien return status; 105153477Sobrien} 105253477Sobrien 105353477Sobrienstatic int 1054131557Stjrgrepdir (char const *dir, struct stats const *stats) 105553477Sobrien{ 105653477Sobrien int status = 1; 1057131557Stjr struct stats const *ancestor; 105853477Sobrien char *name_space; 105953477Sobrien 1060131557Stjr /* Mingw32 does not support st_ino. No known working hosts use zero 1061131557Stjr for st_ino, so assume that the Mingw32 bug applies if it's zero. */ 1062131557Stjr if (stats->stat.st_ino) 1063131557Stjr for (ancestor = stats; (ancestor = ancestor->parent) != 0; ) 1064131557Stjr if (ancestor->stat.st_ino == stats->stat.st_ino 1065131557Stjr && ancestor->stat.st_dev == stats->stat.st_dev) 1066131557Stjr { 1067131557Stjr if (!suppress_errors) 1068141847Sobrien error (0, 0, _("warning: %s: %s"), dir, 106953477Sobrien _("recursive directory loop")); 1070131557Stjr return 1; 1071131557Stjr } 107253477Sobrien 1073131557Stjr name_space = savedir (dir, stats->stat.st_size, included_patterns, 1074131557Stjr excluded_patterns); 107553477Sobrien 107653477Sobrien if (! name_space) 107753477Sobrien { 107853477Sobrien if (errno) 1079131557Stjr suppressible_error (dir, errno); 108053477Sobrien else 1081131557Stjr xalloc_die (); 108253477Sobrien } 108353477Sobrien else 108453477Sobrien { 108553477Sobrien size_t dirlen = strlen (dir); 108653477Sobrien int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir) 108753477Sobrien || IS_SLASH (dir[dirlen - 1])); 108853477Sobrien char *file = NULL; 1089131557Stjr char const *namep = name_space; 109053477Sobrien struct stats child; 109153477Sobrien child.parent = stats; 109253477Sobrien out_file += !no_filenames; 109353477Sobrien while (*namep) 109453477Sobrien { 109553477Sobrien size_t namelen = strlen (namep); 109653477Sobrien file = xrealloc (file, dirlen + 1 + namelen + 1); 109753477Sobrien strcpy (file, dir); 109853477Sobrien file[dirlen] = '/'; 109953477Sobrien strcpy (file + dirlen + needs_slash, namep); 110053477Sobrien namep += namelen + 1; 110153477Sobrien status &= grepfile (file, &child); 110253477Sobrien } 110353477Sobrien out_file -= !no_filenames; 110453477Sobrien if (file) 110553477Sobrien free (file); 110653477Sobrien free (name_space); 110753477Sobrien } 110853477Sobrien 110953477Sobrien return status; 111053477Sobrien} 111153477Sobrien 111253451Speterstatic void 111356920Sruusage (int status) 111453451Speter{ 111553477Sobrien if (status != 0) 111653477Sobrien { 1117131557Stjr fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"), 1118131557Stjr program_name); 1119131557Stjr fprintf (stderr, _("Try `%s --help' for more information.\n"), 1120131557Stjr program_name); 112153477Sobrien } 112253477Sobrien else 112353477Sobrien { 1124131557Stjr printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name); 112553477Sobrien printf (_("\ 112653477SobrienSearch for PATTERN in each FILE or standard input.\n\ 112756920SruExample: %s -i 'hello world' menu.h main.c\n\ 112853477Sobrien\n\ 1129131557StjrRegexp selection and interpretation:\n"), program_name); 113055379Sobrien printf (_("\ 113153477Sobrien -E, --extended-regexp PATTERN is an extended regular expression\n\ 113255379Sobrien -F, --fixed-strings PATTERN is a set of newline-separated strings\n\ 1133131557Stjr -G, --basic-regexp PATTERN is a basic regular expression\n\ 1134131557Stjr -P, --perl-regexp PATTERN is a Perl regular expression\n")); 113555379Sobrien printf (_("\ 113653477Sobrien -e, --regexp=PATTERN use PATTERN as a regular expression\n\ 113753477Sobrien -f, --file=FILE obtain PATTERN from FILE\n\ 113853477Sobrien -i, --ignore-case ignore case distinctions\n\ 113953477Sobrien -w, --word-regexp force PATTERN to match only whole words\n\ 114055379Sobrien -x, --line-regexp force PATTERN to match only whole lines\n\ 114155379Sobrien -z, --null-data a data line ends in 0 byte, not newline\n")); 114253477Sobrien printf (_("\ 114353477Sobrien\n\ 114453477SobrienMiscellaneous:\n\ 114553477Sobrien -s, --no-messages suppress error messages\n\ 114655379Sobrien -v, --invert-match select non-matching lines\n\ 114753477Sobrien -V, --version print version information and exit\n\ 114855379Sobrien --help display this help and exit\n\ 1149103372Sobrien -J, --bz2decompress decompress bzip2'ed input before searching\n\ 115053477Sobrien -Z, --decompress decompress input before searching (HAVE_LIBZ=1)\n\ 115155379Sobrien --mmap use memory-mapped input if possible\n")); 115253477Sobrien printf (_("\ 115353477Sobrien\n\ 115453477SobrienOutput control:\n\ 1155131557Stjr -m, --max-count=NUM stop after NUM matches\n\ 115653477Sobrien -b, --byte-offset print the byte offset with output lines\n\ 115753477Sobrien -n, --line-number print line number with output lines\n\ 1158131557Stjr --line-buffered flush output on every line\n\ 115953477Sobrien -H, --with-filename print the filename for each match\n\ 116053477Sobrien -h, --no-filename suppress the prefixing filename on output\n\ 1161131557Stjr --label=LABEL print LABEL as filename for standard input\n\ 1162131557Stjr -o, --only-matching show only the part of a line matching PATTERN\n\ 116353477Sobrien -q, --quiet, --silent suppress all normal output\n\ 116456233Sru --binary-files=TYPE assume that binary files are TYPE\n\ 1165131557Stjr TYPE is 'binary', 'text', or 'without-match'\n\ 116656920Sru -a, --text equivalent to --binary-files=text\n\ 116756920Sru -I equivalent to --binary-files=without-match\n\ 116853477Sobrien -d, --directories=ACTION how to handle directories\n\ 1169131557Stjr ACTION is 'read', 'recurse', or 'skip'\n\ 1170131557Stjr -D, --devices=ACTION how to handle devices, FIFOs and sockets\n\ 1171131557Stjr ACTION is 'read' or 'skip'\n\ 1172131557Stjr -R, -r, --recursive equivalent to --directories=recurse\n\ 1173131557Stjr --include=PATTERN files that match PATTERN will be examined\n\ 1174131557Stjr --exclude=PATTERN files that match PATTERN will be skipped.\n\ 1175131557Stjr --exclude-from=FILE files that match PATTERN in FILE will be skipped.\n\ 117653477Sobrien -L, --files-without-match only print FILE names containing no match\n\ 117753477Sobrien -l, --files-with-matches only print FILE names containing matches\n\ 117855379Sobrien -c, --count only print a count of matching lines per FILE\n\ 117955379Sobrien --null print 0 byte after FILE name\n")); 118053477Sobrien printf (_("\ 118153477Sobrien\n\ 118253477SobrienContext control:\n\ 118353477Sobrien -B, --before-context=NUM print NUM lines of leading context\n\ 118453477Sobrien -A, --after-context=NUM print NUM lines of trailing context\n\ 1185131557Stjr -C, --context=NUM print NUM lines of output context\n\ 118653477Sobrien -NUM same as --context=NUM\n\ 1187131557Stjr --color[=WHEN],\n\ 1188131557Stjr --colour[=WHEN] use markers to distinguish the matching string\n\ 1189131557Stjr WHEN may be `always', `never' or `auto'.\n\ 119053477Sobrien -U, --binary do not strip CR characters at EOL (MSDOS)\n\ 119153477Sobrien -u, --unix-byte-offsets report offsets as if CRs were not there (MSDOS)\n\ 119253477Sobrien\n\ 119355379Sobrien`egrep' means `grep -E'. `fgrep' means `grep -F'.\n\ 119455379SobrienWith no FILE, or when FILE is -, read standard input. If less than\n\ 119555379Sobrientwo FILEs given, assume -h. Exit status is 0 if match, 1 if no match,\n\ 119655379Sobrienand 2 if trouble.\n")); 119753477Sobrien printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n")); 119853477Sobrien } 119953477Sobrien exit (status); 120053451Speter} 120153451Speter 120255379Sobrien/* Set the matcher to M, reporting any conflicts. */ 120355379Sobrienstatic void 120456920Srusetmatcher (char const *m) 120555379Sobrien{ 120655379Sobrien if (matcher && strcmp (matcher, m) != 0) 1207131557Stjr error (2, 0, _("conflicting matchers specified")); 120855379Sobrien matcher = m; 120955379Sobrien} 121055379Sobrien 121153451Speter/* Go through the matchers vector and look for the specified matcher. 121253451Speter If we find it, install it in compile and execute, and return 1. */ 121353477Sobrienstatic int 121456920Sruinstall_matcher (char const *name) 121553451Speter{ 121653451Speter int i; 1217131557Stjr#if defined(HAVE_SETRLIMIT) 121853477Sobrien struct rlimit rlim; 121953477Sobrien#endif 122053451Speter 1221131557Stjr for (i = 0; matchers[i].compile; i++) 122253477Sobrien if (strcmp (name, matchers[i].name) == 0) 122353451Speter { 122453451Speter compile = matchers[i].compile; 122553451Speter execute = matchers[i].execute; 1226131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK) 122753477Sobrien /* I think every platform needs to do this, so that regex.c 122853477Sobrien doesn't oveflow the stack. The default value of 122953477Sobrien `re_max_failures' is too large for some platforms: it needs 123053477Sobrien more than 3MB-large stack. 123153477Sobrien 123253477Sobrien The test for HAVE_SETRLIMIT should go into `configure'. */ 123353477Sobrien if (!getrlimit (RLIMIT_STACK, &rlim)) 123453477Sobrien { 123553477Sobrien long newlim; 123653477Sobrien extern long int re_max_failures; /* from regex.c */ 123753477Sobrien 123853477Sobrien /* Approximate the amount regex.c needs, plus some more. */ 123953477Sobrien newlim = re_max_failures * 2 * 20 * sizeof (char *); 124053477Sobrien if (newlim > rlim.rlim_max) 124153477Sobrien { 124253477Sobrien newlim = rlim.rlim_max; 124353477Sobrien re_max_failures = newlim / (2 * 20 * sizeof (char *)); 124453477Sobrien } 124553477Sobrien if (rlim.rlim_cur < newlim) 1246131557Stjr { 1247131557Stjr rlim.rlim_cur = newlim; 1248131557Stjr setrlimit (RLIMIT_STACK, &rlim); 1249131557Stjr } 125053477Sobrien } 125153477Sobrien#endif 125253451Speter return 1; 125353451Speter } 125453451Speter return 0; 125553451Speter} 125653451Speter 125753705Sobrien/* Find the white-space-separated options specified by OPTIONS, and 125853705Sobrien using BUF to store copies of these options, set ARGV[0], ARGV[1], 125953705Sobrien etc. to the option copies. Return the number N of options found. 126053705Sobrien Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0] 126153705Sobrien etc. Backslash can be used to escape whitespace (and backslashes). */ 126253705Sobrienstatic int 126356920Sruprepend_args (char const *options, char *buf, char **argv) 126453705Sobrien{ 126553705Sobrien char const *o = options; 126653705Sobrien char *b = buf; 126753705Sobrien int n = 0; 126853705Sobrien 126953705Sobrien for (;;) 127053705Sobrien { 127153705Sobrien while (ISSPACE ((unsigned char) *o)) 127253705Sobrien o++; 127353705Sobrien if (!*o) 127453705Sobrien return n; 127553705Sobrien if (argv) 127653705Sobrien argv[n] = b; 127753705Sobrien n++; 127853705Sobrien 127953705Sobrien do 128053705Sobrien if ((*b++ = *o++) == '\\' && *o) 128153705Sobrien b[-1] = *o++; 128253705Sobrien while (*o && ! ISSPACE ((unsigned char) *o)); 128353705Sobrien 128453705Sobrien *b++ = '\0'; 128553705Sobrien } 128653705Sobrien} 128753705Sobrien 128853705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument 128953705Sobrien vector of a main program with argument count *PARGC and argument 129053705Sobrien vector *PARGV. */ 129153705Sobrienstatic void 129256920Sruprepend_default_options (char const *options, int *pargc, char ***pargv) 129353705Sobrien{ 129453705Sobrien if (options) 129553705Sobrien { 129653705Sobrien char *buf = xmalloc (strlen (options) + 1); 129753705Sobrien int prepended = prepend_args (options, buf, (char **) NULL); 129853705Sobrien int argc = *pargc; 129953705Sobrien char * const *argv = *pargv; 130053705Sobrien char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); 130153705Sobrien *pargc = prepended + argc; 130253705Sobrien *pargv = pp; 130353705Sobrien *pp++ = *argv++; 130453705Sobrien pp += prepend_args (options, buf, pp); 130553705Sobrien while ((*pp++ = *argv++)) 130653705Sobrien continue; 130753705Sobrien } 130853705Sobrien} 130953705Sobrien 1310131557Stjr/* Get the next non-digit option from ARGC and ARGV. 1311131557Stjr Return -1 if there are no more options. 1312131557Stjr Process any digit options that were encountered on the way, 1313131557Stjr and store the resulting integer into *DEFAULT_CONTEXT. */ 1314131557Stjrstatic int 1315131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context) 1316131557Stjr{ 1317131557Stjr int opt; 1318131557Stjr char buf[sizeof (uintmax_t) * CHAR_BIT + 4]; 1319131557Stjr char *p = buf; 1320131557Stjr 1321131557Stjr /* Set buf[0] to anything but '0', for the leading-zero test below. */ 1322131557Stjr buf[0] = '\0'; 1323131557Stjr 1324131557Stjr while (opt = getopt_long (argc, argv, short_options, long_options, NULL), 1325131557Stjr '0' <= opt && opt <= '9') 1326131557Stjr { 1327131557Stjr /* Suppress trivial leading zeros, to avoid incorrect 1328131557Stjr diagnostic on strings like 00000000000. */ 1329131557Stjr p -= buf[0] == '0'; 1330131557Stjr 1331131557Stjr *p++ = opt; 1332131557Stjr if (p == buf + sizeof buf - 4) 1333131557Stjr { 1334131557Stjr /* Too many digits. Append "..." to make context_length_arg 1335131557Stjr complain about "X...", where X contains the digits seen 1336131557Stjr so far. */ 1337131557Stjr strcpy (p, "..."); 1338131557Stjr p += 3; 1339131557Stjr break; 1340131557Stjr } 1341131557Stjr } 1342131557Stjr if (p != buf) 1343131557Stjr { 1344131557Stjr *p = '\0'; 1345131557Stjr context_length_arg (buf, default_context); 1346131557Stjr } 1347131557Stjr 1348131557Stjr return opt; 1349131557Stjr} 1350131557Stjr 135153451Speterint 135256920Srumain (int argc, char **argv) 135353451Speter{ 135453451Speter char *keys; 1355250823Spfg size_t cc, keycc, oldcc, keyalloc; 135653477Sobrien int with_filenames; 1357250823Spfg int opt, status; 135856920Sru int default_context; 135953451Speter FILE *fp; 136053451Speter extern char *optarg; 136153451Speter extern int optind; 136253477Sobrien 136353477Sobrien initialize_main (&argc, &argv); 1364131557Stjr program_name = argv[0]; 1365131557Stjr if (program_name && strrchr (program_name, '/')) 1366131557Stjr program_name = strrchr (program_name, '/') + 1; 136753477Sobrien 1368151534Sjkim if (program_name[0] == 'b' && program_name[1] == 'z') { 1369151527Sjkim BZflag = 1; 1370151527Sjkim program_name += 2; 1371151527Sjkim } 137253477Sobrien#if HAVE_LIBZ > 0 1373151534Sjkim else if (program_name[0] == 'z') { 137453477Sobrien Zflag = 1; 1375131557Stjr ++program_name; 137653477Sobrien } 137753451Speter#endif 137853451Speter 137953477Sobrien#if defined(__MSDOS__) || defined(_WIN32) 138053477Sobrien /* DOS and MS-Windows use backslashes as directory separators, and usually 138153477Sobrien have an .exe suffix. They also have case-insensitive filesystems. */ 1382131557Stjr if (program_name) 138353477Sobrien { 1384131557Stjr char *p = program_name; 138553477Sobrien char *bslash = strrchr (argv[0], '\\'); 138653477Sobrien 1387131557Stjr if (bslash && bslash >= program_name) /* for mixed forward/backslash case */ 1388131557Stjr program_name = bslash + 1; 1389131557Stjr else if (program_name == argv[0] 139053477Sobrien && argv[0][0] && argv[0][1] == ':') /* "c:progname" */ 1391131557Stjr program_name = argv[0] + 2; 139253477Sobrien 139353477Sobrien /* Collapse the letter-case, so `strcmp' could be used hence. */ 139453477Sobrien for ( ; *p; p++) 139553477Sobrien if (*p >= 'A' && *p <= 'Z') 139653477Sobrien *p += 'a' - 'A'; 139753477Sobrien 139853477Sobrien /* Remove the .exe extension, if any. */ 1399131557Stjr if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0) 140053477Sobrien *p = '\0'; 140153477Sobrien } 140253451Speter#endif 140353451Speter 140453451Speter keys = NULL; 140553451Speter keycc = 0; 140653477Sobrien with_filenames = 0; 140755379Sobrien eolbyte = '\n'; 140855379Sobrien filename_mask = ~0; 140953477Sobrien 1410131557Stjr max_count = TYPE_MAXIMUM (off_t); 1411131557Stjr 141253477Sobrien /* The value -1 means to use DEFAULT_CONTEXT. */ 141353477Sobrien out_after = out_before = -1; 141453477Sobrien /* Default before/after context: chaged by -C/-NUM options */ 141553477Sobrien default_context = 0; 1416131557Stjr /* Changed by -o option */ 1417131557Stjr only_matching = 0; 141853477Sobrien 1419131557Stjr /* Internationalization. */ 1420131557Stjr#if defined(HAVE_SETLOCALE) 142153477Sobrien setlocale (LC_ALL, ""); 142253451Speter#endif 1423131557Stjr#if defined(ENABLE_NLS) 142453477Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 142553477Sobrien textdomain (PACKAGE); 142653451Speter#endif 142753451Speter 1428131557Stjr atexit (close_stdout); 1429131557Stjr 143053705Sobrien prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv); 143153705Sobrien 1432131557Stjr while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1) 143353451Speter switch (opt) 143453451Speter { 143553451Speter case 'A': 1436131557Stjr context_length_arg (optarg, &out_after); 143753451Speter break; 1438131557Stjr 143953451Speter case 'B': 1440131557Stjr context_length_arg (optarg, &out_before); 144153451Speter break; 1442131557Stjr 144353451Speter case 'C': 144453477Sobrien /* Set output match context, but let any explicit leading or 144553477Sobrien trailing amount specified with -A or -B stand. */ 1446131557Stjr context_length_arg (optarg, &default_context); 1447131557Stjr break; 1448131557Stjr 1449131557Stjr case 'D': 1450131557Stjr if (strcmp (optarg, "read") == 0) 1451131557Stjr devices = READ_DEVICES; 1452131557Stjr else if (strcmp (optarg, "skip") == 0) 1453131557Stjr devices = SKIP_DEVICES; 145453477Sobrien else 1455131557Stjr error (2, 0, _("unknown devices method")); 145653451Speter break; 1457131557Stjr 145853451Speter case 'E': 145955379Sobrien setmatcher ("egrep"); 146053451Speter break; 1461131557Stjr 146253451Speter case 'F': 146355379Sobrien setmatcher ("fgrep"); 146453451Speter break; 1465131557Stjr 1466131557Stjr case 'P': 1467131557Stjr setmatcher ("perl"); 1468131557Stjr break; 1469131557Stjr 147053451Speter case 'G': 147155379Sobrien setmatcher ("grep"); 147253451Speter break; 1473131557Stjr 147453477Sobrien case 'H': 147553477Sobrien with_filenames = 1; 147653477Sobrien break; 1477131557Stjr 147856920Sru case 'I': 147956920Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 148056920Sru break; 1481103372Sobrien case 'J': 1482104555Sobrien if (Zflag) 1483104555Sobrien { 1484104555Sobrien printf (_("Cannot mix -Z and -J.\n")); 1485104555Sobrien usage (2); 1486104555Sobrien } 1487103372Sobrien BZflag = 1; 1488103372Sobrien break; 1489131557Stjr 149055379Sobrien case 'U': 1491131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 149253477Sobrien dos_use_file_type = DOS_BINARY; 149355379Sobrien#endif 149453477Sobrien break; 1495131557Stjr 149653477Sobrien case 'u': 1497131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 149853477Sobrien dos_report_unix_offset = 1; 149955379Sobrien#endif 150053477Sobrien break; 1501131557Stjr 150253451Speter case 'V': 150353477Sobrien show_version = 1; 150453451Speter break; 1505131557Stjr 150653451Speter case 'X': 150755379Sobrien setmatcher (optarg); 150853451Speter break; 1509131557Stjr 151053451Speter case 'a': 151156233Sru binary_files = TEXT_BINARY_FILES; 151253451Speter break; 1513131557Stjr 151453451Speter case 'b': 151553451Speter out_byte = 1; 151653451Speter break; 1517131557Stjr 151853451Speter case 'c': 151953451Speter count_matches = 1; 152053451Speter break; 1521131557Stjr 152253477Sobrien case 'd': 152353477Sobrien if (strcmp (optarg, "read") == 0) 152453477Sobrien directories = READ_DIRECTORIES; 152553477Sobrien else if (strcmp (optarg, "skip") == 0) 152653477Sobrien directories = SKIP_DIRECTORIES; 152753477Sobrien else if (strcmp (optarg, "recurse") == 0) 152853477Sobrien directories = RECURSE_DIRECTORIES; 152953477Sobrien else 1530131557Stjr error (2, 0, _("unknown directories method")); 153153477Sobrien break; 1532131557Stjr 153353451Speter case 'e': 153453477Sobrien cc = strlen (optarg); 153553477Sobrien keys = xrealloc (keys, keycc + cc + 1); 153653477Sobrien strcpy (&keys[keycc], optarg); 153753451Speter keycc += cc; 153853477Sobrien keys[keycc++] = '\n'; 153953451Speter break; 1540131557Stjr 154153451Speter case 'f': 154253477Sobrien fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin; 154353451Speter if (!fp) 1544131557Stjr error (2, errno, "%s", optarg); 154553477Sobrien for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2) 154653451Speter ; 154753477Sobrien keys = xrealloc (keys, keyalloc); 154853451Speter oldcc = keycc; 154953477Sobrien while (!feof (fp) 155053477Sobrien && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0) 155153451Speter { 155253451Speter keycc += cc; 155353477Sobrien if (keycc == keyalloc - 1) 155453477Sobrien keys = xrealloc (keys, keyalloc *= 2); 155553451Speter } 155653451Speter if (fp != stdin) 155753451Speter fclose(fp); 155853477Sobrien /* Append final newline if file ended in non-newline. */ 155953477Sobrien if (oldcc != keycc && keys[keycc - 1] != '\n') 156053477Sobrien keys[keycc++] = '\n'; 156153451Speter break; 1562131557Stjr 156353451Speter case 'h': 156453451Speter no_filenames = 1; 156553451Speter break; 1566131557Stjr 156753451Speter case 'i': 156853451Speter case 'y': /* For old-timers . . . */ 156953451Speter match_icase = 1; 157053451Speter break; 1571131557Stjr 157253451Speter case 'L': 157353451Speter /* Like -l, except list files that don't contain matches. 157453451Speter Inspired by the same option in Hume's gre. */ 157553451Speter list_files = -1; 157653451Speter break; 1577131557Stjr 157853451Speter case 'l': 157953451Speter list_files = 1; 158053451Speter break; 1581131557Stjr 1582131557Stjr case 'm': 1583131557Stjr { 1584131557Stjr uintmax_t value; 1585131557Stjr switch (xstrtoumax (optarg, 0, 10, &value, "")) 1586131557Stjr { 1587131557Stjr case LONGINT_OK: 1588131557Stjr max_count = value; 1589131557Stjr if (0 <= max_count && max_count == value) 1590131557Stjr break; 1591131557Stjr /* Fall through. */ 1592131557Stjr case LONGINT_OVERFLOW: 1593131557Stjr max_count = TYPE_MAXIMUM (off_t); 1594131557Stjr break; 1595131557Stjr 1596131557Stjr default: 1597131557Stjr error (2, 0, _("invalid max count")); 1598131557Stjr } 1599131557Stjr } 1600131557Stjr break; 1601131557Stjr 160253451Speter case 'n': 160353451Speter out_line = 1; 160453451Speter break; 1605131557Stjr 1606131557Stjr case 'o': 1607131557Stjr only_matching = 1; 1608131557Stjr break; 1609131557Stjr 161053451Speter case 'q': 1611131557Stjr exit_on_match = 1; 1612131557Stjr close_stdout_set_status(0); 161353451Speter break; 1614131557Stjr 161553478Sobrien case 'R': 161653477Sobrien case 'r': 161753477Sobrien directories = RECURSE_DIRECTORIES; 161853477Sobrien break; 1619131557Stjr 162053451Speter case 's': 162153451Speter suppress_errors = 1; 162253451Speter break; 1623131557Stjr 162453451Speter case 'v': 162553451Speter out_invert = 1; 162653451Speter break; 1627131557Stjr 162853451Speter case 'w': 162953451Speter match_words = 1; 163053451Speter break; 1631131557Stjr 163253451Speter case 'x': 163353451Speter match_lines = 1; 163453451Speter break; 1635131557Stjr 163655379Sobrien case 'Z': 163755379Sobrien#if HAVE_LIBZ > 0 1638104555Sobrien if (BZflag) 1639104555Sobrien { 1640104555Sobrien printf (_("Cannot mix -J and -Z.\n")); 1641104555Sobrien usage (2); 1642104555Sobrien } 164355379Sobrien Zflag = 1; 164455379Sobrien#else 164555379Sobrien filename_mask = 0; 164655379Sobrien#endif 164755379Sobrien break; 1648131557Stjr 164955379Sobrien case 'z': 165055379Sobrien eolbyte = '\0'; 165155379Sobrien break; 1652131557Stjr 165356233Sru case BINARY_FILES_OPTION: 165456233Sru if (strcmp (optarg, "binary") == 0) 165556233Sru binary_files = BINARY_BINARY_FILES; 165656233Sru else if (strcmp (optarg, "text") == 0) 165756233Sru binary_files = TEXT_BINARY_FILES; 165856233Sru else if (strcmp (optarg, "without-match") == 0) 165956233Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 166056233Sru else 1661131557Stjr error (2, 0, _("unknown binary-files type")); 166256233Sru break; 1663131557Stjr 1664131557Stjr case COLOR_OPTION: 1665131557Stjr if(optarg) { 1666131557Stjr if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") || 1667131557Stjr !strcasecmp(optarg, "force")) 1668131557Stjr color_option = 1; 1669131557Stjr else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") || 1670131557Stjr !strcasecmp(optarg, "none")) 1671131557Stjr color_option = 0; 1672131557Stjr else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") || 1673131557Stjr !strcasecmp(optarg, "if-tty")) 1674131557Stjr color_option = 2; 1675131557Stjr else 1676131557Stjr show_help = 1; 1677131557Stjr } else 1678131557Stjr color_option = 2; 1679131557Stjr if(color_option == 2) { 1680131557Stjr if(isatty(STDOUT_FILENO) && getenv("TERM") && 1681131557Stjr strcmp(getenv("TERM"), "dumb")) 1682131557Stjr color_option = 1; 1683131557Stjr else 1684131557Stjr color_option = 0; 1685131557Stjr } 1686131557Stjr break; 1687131557Stjr 1688131557Stjr case EXCLUDE_OPTION: 1689131557Stjr if (!excluded_patterns) 1690131557Stjr excluded_patterns = new_exclude (); 1691131557Stjr add_exclude (excluded_patterns, optarg); 1692131557Stjr break; 1693131557Stjr 1694131557Stjr case EXCLUDE_FROM_OPTION: 1695131557Stjr if (!excluded_patterns) 1696131557Stjr excluded_patterns = new_exclude (); 1697131557Stjr if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n') 1698131557Stjr != 0) 1699131557Stjr { 1700131557Stjr error (2, errno, "%s", optarg); 1701131557Stjr } 1702131557Stjr break; 1703131557Stjr 1704131557Stjr case INCLUDE_OPTION: 1705131557Stjr if (!included_patterns) 1706131557Stjr included_patterns = new_exclude (); 1707131557Stjr add_exclude (included_patterns, optarg); 1708131557Stjr break; 1709131557Stjr 1710131557Stjr case LINE_BUFFERED_OPTION: 1711131557Stjr line_buffered = 1; 1712131557Stjr break; 1713131557Stjr 1714131557Stjr case LABEL_OPTION: 1715131557Stjr label = optarg; 1716131557Stjr break; 1717131557Stjr 171853477Sobrien case 0: 171953477Sobrien /* long options */ 172053477Sobrien break; 1721131557Stjr 172253451Speter default: 172353477Sobrien usage (2); 172453451Speter break; 1725131557Stjr 172653451Speter } 172753451Speter 1728131557Stjr /* POSIX.2 says that -q overrides -l, which in turn overrides the 1729131557Stjr other output options. */ 1730131557Stjr if (exit_on_match) 1731131557Stjr list_files = 0; 1732131557Stjr if (exit_on_match | list_files) 1733131557Stjr { 1734131557Stjr count_matches = 0; 1735131557Stjr done_on_match = 1; 1736131557Stjr } 1737131557Stjr out_quiet = count_matches | done_on_match; 1738131557Stjr 173953477Sobrien if (out_after < 0) 174053477Sobrien out_after = default_context; 174153477Sobrien if (out_before < 0) 174253477Sobrien out_before = default_context; 174353477Sobrien 1744131557Stjr if (color_option) 1745131557Stjr { 1746131557Stjr char *userval = getenv ("GREP_COLOR"); 1747131557Stjr if (userval != NULL && *userval != '\0') 1748131557Stjr grep_color = userval; 1749131557Stjr } 1750131557Stjr 175155379Sobrien if (! matcher) 1752131557Stjr matcher = program_name; 175355379Sobrien 175453477Sobrien if (show_version) 175553477Sobrien { 175655379Sobrien printf (_("%s (GNU grep) %s\n"), matcher, VERSION); 175753477Sobrien printf ("\n"); 175853477Sobrien printf (_("\ 1759131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n")); 176053477Sobrien printf (_("\ 176153477SobrienThis is free software; see the source for copying conditions. There is NO\n\ 176253477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")); 176353477Sobrien printf ("\n"); 176453477Sobrien exit (0); 176553477Sobrien } 176653477Sobrien 176753477Sobrien if (show_help) 176853477Sobrien usage (0); 176953477Sobrien 177053477Sobrien if (keys) 177153477Sobrien { 177253477Sobrien if (keycc == 0) 1773131557Stjr { 1774131557Stjr /* No keys were specified (e.g. -f /dev/null). Match nothing. */ 1775131557Stjr out_invert ^= 1; 1776131557Stjr match_lines = match_words = 0; 1777131557Stjr } 177853477Sobrien else 177953477Sobrien /* Strip trailing newline. */ 178053477Sobrien --keycc; 178153477Sobrien } 178253477Sobrien else 178353451Speter if (optind < argc) 178453451Speter { 178553451Speter keys = argv[optind++]; 178653477Sobrien keycc = strlen (keys); 178753451Speter } 178853451Speter else 178953477Sobrien usage (2); 179053451Speter 179155379Sobrien if (!install_matcher (matcher) && !install_matcher ("default")) 179253477Sobrien abort (); 179353451Speter 1794131564Stjr#ifdef MBS_SUPPORT 1795131564Stjr if (MB_CUR_MAX != 1 && match_icase) 1796131564Stjr { 1797131564Stjr wchar_t wc; 1798131564Stjr mbstate_t cur_state, prev_state; 1799131564Stjr int i, len = strlen(keys); 1800131564Stjr 1801131564Stjr memset(&cur_state, 0, sizeof(mbstate_t)); 1802131564Stjr for (i = 0; i <= len ;) 1803131564Stjr { 1804131564Stjr size_t mbclen; 1805131564Stjr mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state); 1806131564Stjr if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0) 1807131564Stjr { 1808131564Stjr /* An invalid sequence, or a truncated multibyte character. 1809131564Stjr We treat it as a singlebyte character. */ 1810131564Stjr mbclen = 1; 1811131564Stjr } 1812131564Stjr else 1813131564Stjr { 1814131564Stjr if (iswupper((wint_t)wc)) 1815131564Stjr { 1816131564Stjr wc = towlower((wint_t)wc); 1817131564Stjr wcrtomb(keys + i, wc, &cur_state); 1818131564Stjr } 1819131564Stjr } 1820131564Stjr i += mbclen; 1821131564Stjr } 1822131564Stjr } 1823131564Stjr#endif /* MBS_SUPPORT */ 1824131564Stjr 182553451Speter (*compile)(keys, keycc); 182653451Speter 182753477Sobrien if ((argc - optind > 1 && !no_filenames) || with_filenames) 182853451Speter out_file = 1; 182953451Speter 1830131557Stjr#ifdef SET_BINARY 183153477Sobrien /* Output is set to binary mode because we shouldn't convert 183253477Sobrien NL to CR-LF pairs, especially when grepping binary files. */ 183353477Sobrien if (!isatty (1)) 183453477Sobrien SET_BINARY (1); 183553451Speter#endif 183653451Speter 1837131557Stjr if (max_count == 0) 1838131557Stjr exit (1); 183953451Speter 184053451Speter if (optind < argc) 184153451Speter { 184253477Sobrien status = 1; 184353477Sobrien do 184453451Speter { 184553477Sobrien char *file = argv[optind]; 1846131557Stjr if ((included_patterns || excluded_patterns) 1847131557Stjr && !isdir (file)) 1848131557Stjr { 1849131557Stjr if (included_patterns && 1850131557Stjr ! excluded_filename (included_patterns, file, 0)) 1851131557Stjr continue; 1852131557Stjr if (excluded_patterns && 1853131557Stjr excluded_filename (excluded_patterns, file, 0)) 1854131557Stjr continue; 1855131557Stjr } 185653477Sobrien status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file, 185753477Sobrien &stats_base); 185853451Speter } 185953477Sobrien while ( ++optind < argc); 186053451Speter } 186153477Sobrien else 186253477Sobrien status = grepfile ((char *) NULL, &stats_base); 186353451Speter 1864131557Stjr /* We register via atexit() to test stdout. */ 186553477Sobrien exit (errseen ? 2 : status); 186653451Speter} 1867131557Stjr/* vim:set shiftwidth=2: */ 1868