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 } 30453477Sobrien if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode)) 30553477Sobrien return 0; 306131557Stjr#ifndef DJGPP 307131557Stjr if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode))) 308131557Stjr#else 309131557Stjr if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode))) 310131557Stjr#endif 311131557Stjr return 0; 31253477Sobrien if ( 313103372Sobrien BZflag || 31453451Speter#if HAVE_LIBZ > 0 31553477Sobrien Zflag || 31653451Speter#endif 31755379Sobrien S_ISREG (stats->stat.st_mode)) 31855379Sobrien { 31955379Sobrien if (file) 32055379Sobrien bufoffset = 0; 32155379Sobrien else 32255379Sobrien { 32355379Sobrien bufoffset = lseek (fd, 0, SEEK_CUR); 32455379Sobrien if (bufoffset < 0) 32555379Sobrien { 326131557Stjr error (0, errno, "lseek"); 32755379Sobrien return 0; 32855379Sobrien } 32955379Sobrien } 330131557Stjr#if defined(HAVE_MMAP) 33155379Sobrien initial_bufoffset = bufoffset; 33255379Sobrien bufmapped = mmap_option && bufoffset % pagesize == 0; 33355379Sobrien#endif 33455379Sobrien } 33553451Speter else 33653451Speter { 337131557Stjr#if defined(HAVE_MMAP) 33855379Sobrien bufmapped = 0; 33955379Sobrien#endif 34053451Speter } 34153477Sobrien return 1; 34253451Speter} 34353451Speter 34453451Speter/* Read new stuff into the buffer, saving the specified 34553451Speter amount of old stuff. When we're done, 'bufbeg' points 34653451Speter to the beginning of the buffer contents, and 'buflim' 34755379Sobrien points just after the end. Return zero if there's an error. */ 34853451Speterstatic int 349131557Stjrfillbuf (size_t save, struct stats const *stats) 35053451Speter{ 35155379Sobrien size_t fillsize = 0; 35255379Sobrien int cc = 1; 353131557Stjr char *readbuf; 35455379Sobrien size_t readsize; 35553451Speter 356131557Stjr /* Offset from start of buffer to start of old stuff 35755379Sobrien that we want to save. */ 358131557Stjr size_t saved_offset = buflim - save - buffer; 35955379Sobrien 360131557Stjr if (pagesize <= buffer + bufalloc - buflim) 36153451Speter { 362131557Stjr readbuf = buflim; 363131557Stjr bufbeg = buflim - save; 364131557Stjr } 365131557Stjr else 366131557Stjr { 367131557Stjr size_t minsize = save + pagesize; 368131557Stjr size_t newsize; 36955379Sobrien size_t newalloc; 370131557Stjr char *newbuf; 37153477Sobrien 372131557Stjr /* Grow newsize until it is at least as great as minsize. */ 373131557Stjr for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2) 374131557Stjr if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2) 375131557Stjr xalloc_die (); 376131557Stjr 377131557Stjr /* Try not to allocate more memory than the file size indicates, 378131557Stjr as that might cause unnecessary memory exhaustion if the file 379131557Stjr is large. However, do not use the original file size as a 380131557Stjr heuristic if we've already read past the file end, as most 381131557Stjr likely the file is growing. */ 38255379Sobrien if (S_ISREG (stats->stat.st_mode)) 38355379Sobrien { 38455379Sobrien off_t to_be_read = stats->stat.st_size - bufoffset; 385131557Stjr off_t maxsize_off = save + to_be_read; 386131557Stjr if (0 <= to_be_read && to_be_read <= maxsize_off 387131557Stjr && maxsize_off == (size_t) maxsize_off 388131557Stjr && minsize <= (size_t) maxsize_off 389131557Stjr && (size_t) maxsize_off < newsize) 390131557Stjr newsize = maxsize_off; 39155379Sobrien } 39255379Sobrien 393131557Stjr /* Add enough room so that the buffer is aligned and has room 394131557Stjr for byte sentinels fore and aft. */ 395131557Stjr newalloc = newsize + pagesize + 1; 39655379Sobrien 397131557Stjr newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer; 398131557Stjr readbuf = ALIGN_TO (newbuf + 1 + save, pagesize); 399131557Stjr bufbeg = readbuf - save; 400131557Stjr memmove (bufbeg, buffer + saved_offset, save); 401131557Stjr bufbeg[-1] = eolbyte; 402131557Stjr if (newbuf != buffer) 40355379Sobrien { 404131557Stjr free (buffer); 405131557Stjr buffer = newbuf; 40655379Sobrien } 40753451Speter } 40853451Speter 409131557Stjr readsize = buffer + bufalloc - readbuf; 410131557Stjr readsize -= readsize % pagesize; 41155379Sobrien 41253477Sobrien#if defined(HAVE_MMAP) 41355379Sobrien if (bufmapped) 41453451Speter { 41555379Sobrien size_t mmapsize = readsize; 41655379Sobrien 41755379Sobrien /* Don't mmap past the end of the file; some hosts don't allow this. 41855379Sobrien Use `read' on the last page. */ 41955379Sobrien if (stats->stat.st_size - bufoffset < mmapsize) 42053451Speter { 42155379Sobrien mmapsize = stats->stat.st_size - bufoffset; 42255379Sobrien mmapsize -= mmapsize % pagesize; 42353451Speter } 42455379Sobrien 42555379Sobrien if (mmapsize 426131557Stjr && (mmap ((caddr_t) readbuf, mmapsize, 42755379Sobrien PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 42855379Sobrien bufdesc, bufoffset) 42955379Sobrien != (caddr_t) -1)) 43053451Speter { 43155379Sobrien /* Do not bother to use madvise with MADV_SEQUENTIAL or 43255379Sobrien MADV_WILLNEED on the mmapped memory. One might think it 43355379Sobrien would help, but it slows us down about 30% on SunOS 4.1. */ 43455379Sobrien fillsize = mmapsize; 43555379Sobrien } 43655379Sobrien else 43755379Sobrien { 43855379Sobrien /* Stop using mmap on this file. Synchronize the file 43955379Sobrien offset. Do not warn about mmap failures. On some hosts 44055379Sobrien (e.g. Solaris 2.5) mmap can fail merely because some 44155379Sobrien other process has an advisory read lock on the file. 44255379Sobrien There's no point alarming the user about this misfeature. */ 44353451Speter bufmapped = 0; 44455379Sobrien if (bufoffset != initial_bufoffset 44555379Sobrien && lseek (bufdesc, bufoffset, SEEK_SET) < 0) 44655379Sobrien { 447131557Stjr error (0, errno, "lseek"); 44855379Sobrien cc = 0; 44955379Sobrien } 45053451Speter } 45155379Sobrien } 45255379Sobrien#endif /*HAVE_MMAP*/ 45355379Sobrien 45455379Sobrien if (! fillsize) 45555379Sobrien { 45655379Sobrien ssize_t bytesread; 45755379Sobrien do 458104555Sobrien if (BZflag && bzbufdesc) 459103372Sobrien { 460104555Sobrien int bzerr; 461131557Stjr bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize); 462104555Sobrien 463104555Sobrien switch (bzerr) 464104555Sobrien { 465104555Sobrien case BZ_OK: 466104555Sobrien case BZ_STREAM_END: 467104555Sobrien /* ok */ 468104555Sobrien break; 469104555Sobrien case BZ_DATA_ERROR_MAGIC: 470104555Sobrien BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL; 471104555Sobrien lseek (bufdesc, 0, SEEK_SET); 472131557Stjr bytesread = read (bufdesc, readbuf, readsize); 473104555Sobrien break; 474104555Sobrien default: 475104555Sobrien bytesread = 0; 476104555Sobrien break; 477104555Sobrien } 478103372Sobrien } 479103372Sobrien else 48053451Speter#if HAVE_LIBZ > 0 48155379Sobrien if (Zflag) 482131557Stjr bytesread = gzread (gzbufdesc, readbuf, readsize); 48355379Sobrien else 48455379Sobrien#endif 485131557Stjr bytesread = read (bufdesc, readbuf, readsize); 48655379Sobrien while (bytesread < 0 && errno == EINTR); 48755379Sobrien if (bytesread < 0) 48855379Sobrien cc = 0; 48953477Sobrien else 49055379Sobrien fillsize = bytesread; 49153451Speter } 49255379Sobrien 49355379Sobrien bufoffset += fillsize; 494131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 49555379Sobrien if (fillsize) 496131557Stjr fillsize = undossify_input (readbuf, fillsize); 49753451Speter#endif 498131557Stjr buflim = readbuf + fillsize; 49953451Speter return cc; 50053451Speter} 50153451Speter 50253451Speter/* Flags controlling the style of output. */ 50356233Srustatic enum 504131557Stjr{ 505131557Stjr BINARY_BINARY_FILES, 506131557Stjr TEXT_BINARY_FILES, 507131557Stjr WITHOUT_MATCH_BINARY_FILES 508131557Stjr} binary_files; /* How to handle binary files. */ 509131557Stjr 510131557Stjrstatic int filename_mask; /* If zero, output nulls after filenames. */ 51153451Speterstatic int out_quiet; /* Suppress all normal output. */ 51253451Speterstatic int out_invert; /* Print nonmatching stuff. */ 51353451Speterstatic int out_file; /* Print filenames. */ 51453451Speterstatic int out_line; /* Print line numbers. */ 51553451Speterstatic int out_byte; /* Print byte offsets. */ 51653451Speterstatic int out_before; /* Lines of leading context. */ 51753451Speterstatic int out_after; /* Lines of trailing context. */ 51853477Sobrienstatic int count_matches; /* Count matching lines. */ 51953477Sobrienstatic int list_files; /* List matching files. */ 52053477Sobrienstatic int no_filenames; /* Suppress file names. */ 521131557Stjrstatic off_t max_count; /* Stop after outputting this many 522131557Stjr lines from an input file. */ 523131557Stjrstatic int line_buffered; /* If nonzero, use line buffering, i.e. 524131557Stjr fflush everyline out. */ 525131557Stjrstatic char *label = NULL; /* Fake filename for stdin */ 52653451Speter 527131557Stjr 52853451Speter/* Internal variables to keep track of byte count, context, etc. */ 529131557Stjrstatic uintmax_t totalcc; /* Total character count before bufbeg. */ 530131557Stjrstatic char const *lastnl; /* Pointer after last newline counted. */ 531131557Stjrstatic char const *lastout; /* Pointer after last character output; 53253451Speter NULL if no character has been output 53353451Speter or if it's conceptually before bufbeg. */ 534131557Stjrstatic uintmax_t totalnl; /* Total newline count before lastnl. */ 535131557Stjrstatic off_t outleft; /* Maximum number of lines to be output. */ 536131557Stjrstatic int pending; /* Pending lines of output. 537131557Stjr Always kept 0 if out_quiet is true. */ 538131557Stjrstatic int done_on_match; /* Stop scanning file on first match. */ 539131557Stjrstatic int exit_on_match; /* Exit on first match. */ 54053451Speter 541131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 54253477Sobrien# include "dosbuf.c" 54353477Sobrien#endif 54453477Sobrien 545131557Stjr/* Add two numbers that count input bytes or lines, and report an 546131557Stjr error if the addition overflows. */ 547131557Stjrstatic uintmax_t 548131557Stjradd_count (uintmax_t a, uintmax_t b) 549131557Stjr{ 550131557Stjr uintmax_t sum = a + b; 551131557Stjr if (sum < a) 552131557Stjr error (2, 0, _("input is too large to count")); 553131557Stjr return sum; 554131557Stjr} 555131557Stjr 55653451Speterstatic void 557131557Stjrnlscan (char const *lim) 55853451Speter{ 559131557Stjr size_t newlines = 0; 560131557Stjr char const *beg; 561131557Stjr for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++) 562131557Stjr newlines++; 563131557Stjr totalnl = add_count (totalnl, newlines); 56455379Sobrien lastnl = lim; 56553451Speter} 56653451Speter 567131557Stjr/* Print a byte offset, followed by a character separator. */ 56853451Speterstatic void 569131557Stjrprint_offset_sep (uintmax_t pos, char sep) 57053477Sobrien{ 571131557Stjr /* Do not rely on printf to print pos, since uintmax_t may be longer 572131557Stjr than long, and long long is not portable. */ 57353477Sobrien 57453477Sobrien char buf[sizeof pos * CHAR_BIT]; 57553477Sobrien char *p = buf + sizeof buf - 1; 57653477Sobrien *p = sep; 57753477Sobrien 57853477Sobrien do 57953477Sobrien *--p = '0' + pos % 10; 58053477Sobrien while ((pos /= 10) != 0); 58153477Sobrien 58253477Sobrien fwrite (p, 1, buf + sizeof buf - p, stdout); 58353477Sobrien} 58453477Sobrien 58553477Sobrienstatic void 586146199Stjrprline (char const *beg, char const *lim, int sep) 58753451Speter{ 58853451Speter if (out_file) 58955379Sobrien printf ("%s%c", filename, sep & filename_mask); 59053451Speter if (out_line) 59153451Speter { 59253477Sobrien nlscan (beg); 593131557Stjr totalnl = add_count (totalnl, 1); 594131557Stjr print_offset_sep (totalnl, sep); 59553451Speter lastnl = lim; 59653451Speter } 59753451Speter if (out_byte) 59853477Sobrien { 599131557Stjr uintmax_t pos = add_count (totalcc, beg - bufbeg); 600131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 60153477Sobrien pos = dossified_pos (pos); 60253477Sobrien#endif 60353477Sobrien print_offset_sep (pos, sep); 60453477Sobrien } 605131557Stjr if (only_matching) 606131557Stjr { 607131557Stjr size_t match_size; 608131557Stjr size_t match_offset; 609146199Stjr while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1)) 610131557Stjr != (size_t) -1) 611131557Stjr { 612131557Stjr char const *b = beg + match_offset; 613131557Stjr if (b == lim) 614131557Stjr break; 615131557Stjr if (match_size == 0) 616131557Stjr break; 617131557Stjr if(color_option) 618131557Stjr printf("\33[%sm", grep_color); 619131557Stjr fwrite(b, sizeof (char), match_size, stdout); 620131557Stjr if(color_option) 621131557Stjr fputs("\33[00m", stdout); 622131557Stjr fputs("\n", stdout); 623131557Stjr beg = b + match_size; 624131557Stjr } 625131557Stjr lastout = lim; 626131557Stjr if(line_buffered) 627131557Stjr fflush(stdout); 628131557Stjr return; 629131557Stjr } 630131557Stjr if (color_option) 631131557Stjr { 632131557Stjr size_t match_size; 633131557Stjr size_t match_offset; 634146199Stjr while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1)) 635131557Stjr != (size_t) -1) 636131557Stjr { 637131557Stjr char const *b = beg + match_offset; 638131557Stjr /* Avoid matching the empty line at the end of the buffer. */ 639131557Stjr if (b == lim) 640131557Stjr break; 641131557Stjr /* Avoid hanging on grep --color "" foo */ 642131557Stjr if (match_size == 0) 643131557Stjr break; 644131557Stjr fwrite (beg, sizeof (char), match_offset, stdout); 645131557Stjr printf ("\33[%sm", grep_color); 646131557Stjr fwrite (b, sizeof (char), match_size, stdout); 647131557Stjr fputs ("\33[00m", stdout); 648131557Stjr beg = b + match_size; 649131557Stjr } 650146203Stjr fputs ("\33[K", stdout); 651131557Stjr } 65253477Sobrien fwrite (beg, 1, lim - beg, stdout); 65353477Sobrien if (ferror (stdout)) 654131557Stjr error (0, errno, _("writing output")); 65553451Speter lastout = lim; 656131557Stjr if (line_buffered) 657131557Stjr fflush (stdout); 65853451Speter} 65953451Speter 660131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends 661131557Stjr at the next matching line when OUTLEFT is 0. */ 66253451Speterstatic void 663146199Stjrprpending (char const *lim) 66453451Speter{ 66553451Speter if (!lastout) 66653451Speter lastout = bufbeg; 66753451Speter while (pending > 0 && lastout < lim) 66853451Speter { 669131557Stjr char const *nl = memchr (lastout, eolbyte, lim - lastout); 670131557Stjr size_t match_size; 67153451Speter --pending; 672131557Stjr if (outleft 673146199Stjr || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1) 674131557Stjr == !out_invert)) 675146199Stjr prline (lastout, nl + 1, '-'); 67653451Speter else 677131557Stjr pending = 0; 67853451Speter } 67953451Speter} 68053451Speter 68153451Speter/* Print the lines between BEG and LIM. Deal with context crap. 682131557Stjr If NLINESP is non-null, store a count of lines between BEG and LIM. */ 68353451Speterstatic void 684146199Stjrprtext (char const *beg, char const *lim, int *nlinesp) 68553451Speter{ 68653451Speter static int used; /* avoid printing "--" before any output */ 687131557Stjr char const *bp, *p; 68855379Sobrien char eol = eolbyte; 68953451Speter int i, n; 69053451Speter 69153451Speter if (!out_quiet && pending > 0) 692146199Stjr prpending (beg); 69353451Speter 69453451Speter p = beg; 69553451Speter 69653451Speter if (!out_quiet) 69753451Speter { 69853451Speter /* Deal with leading context crap. */ 69953451Speter 70053451Speter bp = lastout ? lastout : bufbeg; 70153451Speter for (i = 0; i < out_before; ++i) 70253451Speter if (p > bp) 70353451Speter do 70453451Speter --p; 705131557Stjr while (p[-1] != eol); 70653451Speter 70753451Speter /* We only print the "--" separator if our output is 70853451Speter discontiguous from the last output in the file. */ 70953451Speter if ((out_before || out_after) && used && p != lastout) 71053477Sobrien puts ("--"); 71153451Speter 71253451Speter while (p < beg) 71353451Speter { 714131557Stjr char const *nl = memchr (p, eol, beg - p); 715131557Stjr nl++; 716146199Stjr prline (p, nl, '-'); 717131557Stjr p = nl; 71853451Speter } 71953451Speter } 72053451Speter 72153451Speter if (nlinesp) 72253451Speter { 72353451Speter /* Caller wants a line count. */ 724131557Stjr for (n = 0; p < lim && n < outleft; n++) 72553451Speter { 726131557Stjr char const *nl = memchr (p, eol, lim - p); 727131557Stjr nl++; 72853451Speter if (!out_quiet) 729146199Stjr prline (p, nl, ':'); 73053451Speter p = nl; 73153451Speter } 73253451Speter *nlinesp = n; 733131557Stjr 734131557Stjr /* relying on it that this function is never called when outleft = 0. */ 735131557Stjr after_last_match = bufoffset - (buflim - p); 73653451Speter } 73753451Speter else 73853451Speter if (!out_quiet) 739146199Stjr prline (beg, lim, ':'); 74053451Speter 74155379Sobrien pending = out_quiet ? 0 : out_after; 74253451Speter used = 1; 74353451Speter} 74453451Speter 74553451Speter/* Scan the specified portion of the buffer, matching lines (or 74653451Speter between matching lines if OUT_INVERT is true). Return a count of 74753451Speter lines printed. */ 74853451Speterstatic int 749146199Stjrgrepbuf (char const *beg, char const *lim) 75053451Speter{ 75153451Speter int nlines, n; 752131557Stjr register char const *p; 753131557Stjr size_t match_offset; 754131557Stjr size_t match_size; 75553451Speter 75653451Speter nlines = 0; 75753451Speter p = beg; 758146199Stjr while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1) 75953451Speter { 760131557Stjr char const *b = p + match_offset; 761131557Stjr char const *endp = b + match_size; 76253451Speter /* Avoid matching the empty line at the end of the buffer. */ 763131557Stjr if (b == lim) 76453451Speter break; 76553451Speter if (!out_invert) 76653451Speter { 767146199Stjr prtext (b, endp, (int *) 0); 768131557Stjr nlines++; 769131557Stjr outleft--; 770131557Stjr if (!outleft || done_on_match) 771131557Stjr { 772131557Stjr if (exit_on_match) 773131557Stjr exit (0); 774131557Stjr after_last_match = bufoffset - (buflim - endp); 775131557Stjr return nlines; 776131557Stjr } 77753451Speter } 77853451Speter else if (p < b) 77953451Speter { 780146199Stjr prtext (p, b, &n); 78153451Speter nlines += n; 782131557Stjr outleft -= n; 783131557Stjr if (!outleft) 784131557Stjr return nlines; 78553451Speter } 78653451Speter p = endp; 78753451Speter } 78853451Speter if (out_invert && p < lim) 78953451Speter { 790146199Stjr prtext (p, lim, &n); 79153451Speter nlines += n; 792131557Stjr outleft -= n; 79353451Speter } 79453451Speter return nlines; 79553451Speter} 79653451Speter 79753477Sobrien/* Search a given file. Normally, return a count of lines printed; 79853477Sobrien but if the file is a directory and we search it recursively, then 79953477Sobrien return -2 if there was a match, and -1 otherwise. */ 80053451Speterstatic int 80156920Srugrep (int fd, char const *file, struct stats *stats) 80253451Speter{ 80353451Speter int nlines, i; 80453477Sobrien int not_text; 80553451Speter size_t residue, save; 806131557Stjr char oldc; 807131557Stjr char *beg; 808131557Stjr char *lim; 80955379Sobrien char eol = eolbyte; 81053451Speter 81153477Sobrien if (!reset (fd, file, stats)) 81253477Sobrien return 0; 81353451Speter 81453477Sobrien if (file && directories == RECURSE_DIRECTORIES 81553477Sobrien && S_ISDIR (stats->stat.st_mode)) 81653477Sobrien { 81753477Sobrien /* Close fd now, so that we don't open a lot of file descriptors 81853477Sobrien when we recurse deeply. */ 819104555Sobrien if (BZflag && bzbufdesc) 820103372Sobrien BZ2_bzclose(bzbufdesc); 821103372Sobrien else 82253477Sobrien#if HAVE_LIBZ > 0 82353477Sobrien if (Zflag) 82453477Sobrien gzclose(gzbufdesc); 82553477Sobrien else 82653477Sobrien#endif 82753477Sobrien if (close (fd) != 0) 828131557Stjr error (0, errno, "%s", file); 82953477Sobrien return grepdir (file, stats) - 2; 83053477Sobrien } 83153477Sobrien 83253451Speter totalcc = 0; 83353451Speter lastout = 0; 83453451Speter totalnl = 0; 835131557Stjr outleft = max_count; 836131557Stjr after_last_match = 0; 83753451Speter pending = 0; 83853451Speter 83953451Speter nlines = 0; 84053451Speter residue = 0; 84153451Speter save = 0; 84253451Speter 84355379Sobrien if (! fillbuf (save, stats)) 84453451Speter { 845131557Stjr if (! is_EISDIR (errno, file)) 846131557Stjr suppressible_error (filename, errno); 84756233Sru return 0; 84853477Sobrien } 84953451Speter 85056233Sru not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet) 85156233Sru || binary_files == WITHOUT_MATCH_BINARY_FILES) 85255379Sobrien && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg)); 85356233Sru if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES) 85456233Sru return 0; 85553477Sobrien done_on_match += not_text; 85653477Sobrien out_quiet += not_text; 85753451Speter 85853477Sobrien for (;;) 85953477Sobrien { 86053451Speter lastnl = bufbeg; 86153451Speter if (lastout) 86253451Speter lastout = bufbeg; 863131557Stjr 864131557Stjr beg = bufbeg + save; 865131557Stjr 866131557Stjr /* no more data to scan (eof) except for maybe a residue -> break */ 867131557Stjr if (beg == buflim) 86853451Speter break; 869131557Stjr 870131557Stjr /* Determine new residue (the length of an incomplete line at the end of 871131557Stjr the buffer, 0 means there is no incomplete last line). */ 872131557Stjr oldc = beg[-1]; 873131557Stjr beg[-1] = eol; 874131557Stjr for (lim = buflim; lim[-1] != eol; lim--) 875131557Stjr continue; 876131557Stjr beg[-1] = oldc; 877131557Stjr if (lim == beg) 878131557Stjr lim = beg - residue; 879131557Stjr beg -= residue; 88053451Speter residue = buflim - lim; 881131557Stjr 88253451Speter if (beg < lim) 88353451Speter { 884131557Stjr if (outleft) 885146199Stjr nlines += grepbuf (beg, lim); 88653451Speter if (pending) 887146199Stjr prpending (lim); 888131557Stjr if((!outleft && !pending) || (nlines && done_on_match && !out_invert)) 88953477Sobrien goto finish_grep; 89053451Speter } 891131557Stjr 892131557Stjr /* The last OUT_BEFORE lines at the end of the buffer will be needed as 893131557Stjr leading context if there is a matching line at the begin of the 894131557Stjr next data. Make beg point to their begin. */ 89553451Speter i = 0; 89653451Speter beg = lim; 89753451Speter while (i < out_before && beg > bufbeg && beg != lastout) 89853451Speter { 89953451Speter ++i; 90053451Speter do 90153451Speter --beg; 902131557Stjr while (beg[-1] != eol); 90353451Speter } 904131557Stjr 905131557Stjr /* detect if leading context is discontinuous from last printed line. */ 90653451Speter if (beg != lastout) 90753451Speter lastout = 0; 908131557Stjr 909131557Stjr /* Handle some details and read more data to scan. */ 91053451Speter save = residue + lim - beg; 911131557Stjr if (out_byte) 912131557Stjr totalcc = add_count (totalcc, buflim - bufbeg - save); 91353451Speter if (out_line) 91453477Sobrien nlscan (beg); 91555379Sobrien if (! fillbuf (save, stats)) 91653477Sobrien { 917131557Stjr if (! is_EISDIR (errno, file)) 918131557Stjr suppressible_error (filename, errno); 91953477Sobrien goto finish_grep; 92053477Sobrien } 92153451Speter } 92253451Speter if (residue) 92353451Speter { 92456920Sru *buflim++ = eol; 925131557Stjr if (outleft) 926146199Stjr nlines += grepbuf (bufbeg + save - residue, buflim); 92753451Speter if (pending) 928146199Stjr prpending (buflim); 92953451Speter } 93053477Sobrien 93153477Sobrien finish_grep: 93253477Sobrien done_on_match -= not_text; 93353477Sobrien out_quiet -= not_text; 93453477Sobrien if ((not_text & ~out_quiet) && nlines != 0) 93553477Sobrien printf (_("Binary file %s matches\n"), filename); 93653451Speter return nlines; 93753451Speter} 93853451Speter 93953477Sobrienstatic int 94056920Srugrepfile (char const *file, struct stats *stats) 94153477Sobrien{ 94253477Sobrien int desc; 94353477Sobrien int count; 94453477Sobrien int status; 94553477Sobrien 94653477Sobrien if (! file) 94753477Sobrien { 94853477Sobrien desc = 0; 949131557Stjr filename = label ? label : _("(standard input)"); 95053477Sobrien } 95153477Sobrien else 95253477Sobrien { 95355379Sobrien while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR) 95455379Sobrien continue; 95553477Sobrien 95653477Sobrien if (desc < 0) 95753477Sobrien { 95853477Sobrien int e = errno; 959131557Stjr 96053477Sobrien if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES) 96153477Sobrien { 96253477Sobrien if (stat (file, &stats->stat) != 0) 96353477Sobrien { 964131557Stjr error (0, errno, "%s", file); 96553477Sobrien return 1; 96653477Sobrien } 96753477Sobrien 96853477Sobrien return grepdir (file, stats); 96953477Sobrien } 970131557Stjr 97153477Sobrien if (!suppress_errors) 97253477Sobrien { 97353477Sobrien if (directories == SKIP_DIRECTORIES) 97453477Sobrien switch (e) 97553477Sobrien { 976131557Stjr#if defined(EISDIR) 97753477Sobrien case EISDIR: 97853477Sobrien return 1; 97953451Speter#endif 98053477Sobrien case EACCES: 98153477Sobrien /* When skipping directories, don't worry about 98253477Sobrien directories that can't be opened. */ 983131557Stjr if (isdir (file)) 98453477Sobrien return 1; 98553477Sobrien break; 98653477Sobrien } 98753477Sobrien } 98853477Sobrien 989131557Stjr suppressible_error (file, e); 99053477Sobrien return 1; 99153477Sobrien } 99253477Sobrien 99353477Sobrien filename = file; 99453477Sobrien } 99553477Sobrien 996131557Stjr#if defined(SET_BINARY) 99753477Sobrien /* Set input to binary mode. Pipes are simulated with files 99853477Sobrien on DOS, so this includes the case of "foo | grep bar". */ 99953477Sobrien if (!isatty (desc)) 100053477Sobrien SET_BINARY (desc); 100153477Sobrien#endif 100253477Sobrien 100353477Sobrien count = grep (desc, file, stats); 100453477Sobrien if (count < 0) 100553477Sobrien status = count + 2; 100653477Sobrien else 100753477Sobrien { 100853477Sobrien if (count_matches) 100953477Sobrien { 101053477Sobrien if (out_file) 101155379Sobrien printf ("%s%c", filename, ':' & filename_mask); 101253477Sobrien printf ("%d\n", count); 101353477Sobrien } 101453477Sobrien 101555379Sobrien status = !count; 101655379Sobrien if (list_files == 1 - 2 * status) 101755379Sobrien printf ("%s%c", filename, '\n' & filename_mask); 101853477Sobrien 1019104555Sobrien if (BZflag && bzbufdesc) 1020103372Sobrien BZ2_bzclose(bzbufdesc); 1021103372Sobrien else 102253451Speter#if HAVE_LIBZ > 0 102353477Sobrien if (Zflag) 102453477Sobrien gzclose(gzbufdesc); 102553477Sobrien else 102653451Speter#endif 1027131557Stjr if (! file) 1028131557Stjr { 1029131557Stjr off_t required_offset = outleft ? bufoffset : after_last_match; 1030131557Stjr if ((bufmapped || required_offset != bufoffset) 1031131557Stjr && lseek (desc, required_offset, SEEK_SET) < 0 1032131557Stjr && S_ISREG (stats->stat.st_mode)) 1033131557Stjr error (0, errno, "%s", filename); 1034131557Stjr } 1035131557Stjr else 103655379Sobrien while (close (desc) != 0) 103755379Sobrien if (errno != EINTR) 103855379Sobrien { 1039131557Stjr error (0, errno, "%s", file); 104055379Sobrien break; 104155379Sobrien } 104253477Sobrien } 104353451Speter 104453477Sobrien return status; 104553477Sobrien} 104653477Sobrien 104753477Sobrienstatic int 1048131557Stjrgrepdir (char const *dir, struct stats const *stats) 104953477Sobrien{ 105053477Sobrien int status = 1; 1051131557Stjr struct stats const *ancestor; 105253477Sobrien char *name_space; 105353477Sobrien 1054131557Stjr /* Mingw32 does not support st_ino. No known working hosts use zero 1055131557Stjr for st_ino, so assume that the Mingw32 bug applies if it's zero. */ 1056131557Stjr if (stats->stat.st_ino) 1057131557Stjr for (ancestor = stats; (ancestor = ancestor->parent) != 0; ) 1058131557Stjr if (ancestor->stat.st_ino == stats->stat.st_ino 1059131557Stjr && ancestor->stat.st_dev == stats->stat.st_dev) 1060131557Stjr { 1061131557Stjr if (!suppress_errors) 1062141847Sobrien error (0, 0, _("warning: %s: %s"), dir, 106353477Sobrien _("recursive directory loop")); 1064131557Stjr return 1; 1065131557Stjr } 106653477Sobrien 1067131557Stjr name_space = savedir (dir, stats->stat.st_size, included_patterns, 1068131557Stjr excluded_patterns); 106953477Sobrien 107053477Sobrien if (! name_space) 107153477Sobrien { 107253477Sobrien if (errno) 1073131557Stjr suppressible_error (dir, errno); 107453477Sobrien else 1075131557Stjr xalloc_die (); 107653477Sobrien } 107753477Sobrien else 107853477Sobrien { 107953477Sobrien size_t dirlen = strlen (dir); 108053477Sobrien int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir) 108153477Sobrien || IS_SLASH (dir[dirlen - 1])); 108253477Sobrien char *file = NULL; 1083131557Stjr char const *namep = name_space; 108453477Sobrien struct stats child; 108553477Sobrien child.parent = stats; 108653477Sobrien out_file += !no_filenames; 108753477Sobrien while (*namep) 108853477Sobrien { 108953477Sobrien size_t namelen = strlen (namep); 109053477Sobrien file = xrealloc (file, dirlen + 1 + namelen + 1); 109153477Sobrien strcpy (file, dir); 109253477Sobrien file[dirlen] = '/'; 109353477Sobrien strcpy (file + dirlen + needs_slash, namep); 109453477Sobrien namep += namelen + 1; 109553477Sobrien status &= grepfile (file, &child); 109653477Sobrien } 109753477Sobrien out_file -= !no_filenames; 109853477Sobrien if (file) 109953477Sobrien free (file); 110053477Sobrien free (name_space); 110153477Sobrien } 110253477Sobrien 110353477Sobrien return status; 110453477Sobrien} 110553477Sobrien 110653451Speterstatic void 110756920Sruusage (int status) 110853451Speter{ 110953477Sobrien if (status != 0) 111053477Sobrien { 1111131557Stjr fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"), 1112131557Stjr program_name); 1113131557Stjr fprintf (stderr, _("Try `%s --help' for more information.\n"), 1114131557Stjr program_name); 111553477Sobrien } 111653477Sobrien else 111753477Sobrien { 1118131557Stjr printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name); 111953477Sobrien printf (_("\ 112053477SobrienSearch for PATTERN in each FILE or standard input.\n\ 112156920SruExample: %s -i 'hello world' menu.h main.c\n\ 112253477Sobrien\n\ 1123131557StjrRegexp selection and interpretation:\n"), program_name); 112455379Sobrien printf (_("\ 112553477Sobrien -E, --extended-regexp PATTERN is an extended regular expression\n\ 112655379Sobrien -F, --fixed-strings PATTERN is a set of newline-separated strings\n\ 1127131557Stjr -G, --basic-regexp PATTERN is a basic regular expression\n\ 1128131557Stjr -P, --perl-regexp PATTERN is a Perl regular expression\n")); 112955379Sobrien printf (_("\ 113053477Sobrien -e, --regexp=PATTERN use PATTERN as a regular expression\n\ 113153477Sobrien -f, --file=FILE obtain PATTERN from FILE\n\ 113253477Sobrien -i, --ignore-case ignore case distinctions\n\ 113353477Sobrien -w, --word-regexp force PATTERN to match only whole words\n\ 113455379Sobrien -x, --line-regexp force PATTERN to match only whole lines\n\ 113555379Sobrien -z, --null-data a data line ends in 0 byte, not newline\n")); 113653477Sobrien printf (_("\ 113753477Sobrien\n\ 113853477SobrienMiscellaneous:\n\ 113953477Sobrien -s, --no-messages suppress error messages\n\ 114055379Sobrien -v, --invert-match select non-matching lines\n\ 114153477Sobrien -V, --version print version information and exit\n\ 114255379Sobrien --help display this help and exit\n\ 1143103372Sobrien -J, --bz2decompress decompress bzip2'ed input before searching\n\ 114453477Sobrien -Z, --decompress decompress input before searching (HAVE_LIBZ=1)\n\ 114555379Sobrien --mmap use memory-mapped input if possible\n")); 114653477Sobrien printf (_("\ 114753477Sobrien\n\ 114853477SobrienOutput control:\n\ 1149131557Stjr -m, --max-count=NUM stop after NUM matches\n\ 115053477Sobrien -b, --byte-offset print the byte offset with output lines\n\ 115153477Sobrien -n, --line-number print line number with output lines\n\ 1152131557Stjr --line-buffered flush output on every line\n\ 115353477Sobrien -H, --with-filename print the filename for each match\n\ 115453477Sobrien -h, --no-filename suppress the prefixing filename on output\n\ 1155131557Stjr --label=LABEL print LABEL as filename for standard input\n\ 1156131557Stjr -o, --only-matching show only the part of a line matching PATTERN\n\ 115753477Sobrien -q, --quiet, --silent suppress all normal output\n\ 115856233Sru --binary-files=TYPE assume that binary files are TYPE\n\ 1159131557Stjr TYPE is 'binary', 'text', or 'without-match'\n\ 116056920Sru -a, --text equivalent to --binary-files=text\n\ 116156920Sru -I equivalent to --binary-files=without-match\n\ 116253477Sobrien -d, --directories=ACTION how to handle directories\n\ 1163131557Stjr ACTION is 'read', 'recurse', or 'skip'\n\ 1164131557Stjr -D, --devices=ACTION how to handle devices, FIFOs and sockets\n\ 1165131557Stjr ACTION is 'read' or 'skip'\n\ 1166131557Stjr -R, -r, --recursive equivalent to --directories=recurse\n\ 1167131557Stjr --include=PATTERN files that match PATTERN will be examined\n\ 1168131557Stjr --exclude=PATTERN files that match PATTERN will be skipped.\n\ 1169131557Stjr --exclude-from=FILE files that match PATTERN in FILE will be skipped.\n\ 117053477Sobrien -L, --files-without-match only print FILE names containing no match\n\ 117153477Sobrien -l, --files-with-matches only print FILE names containing matches\n\ 117255379Sobrien -c, --count only print a count of matching lines per FILE\n\ 117355379Sobrien --null print 0 byte after FILE name\n")); 117453477Sobrien printf (_("\ 117553477Sobrien\n\ 117653477SobrienContext control:\n\ 117753477Sobrien -B, --before-context=NUM print NUM lines of leading context\n\ 117853477Sobrien -A, --after-context=NUM print NUM lines of trailing context\n\ 1179131557Stjr -C, --context=NUM print NUM lines of output context\n\ 118053477Sobrien -NUM same as --context=NUM\n\ 1181131557Stjr --color[=WHEN],\n\ 1182131557Stjr --colour[=WHEN] use markers to distinguish the matching string\n\ 1183131557Stjr WHEN may be `always', `never' or `auto'.\n\ 118453477Sobrien -U, --binary do not strip CR characters at EOL (MSDOS)\n\ 118553477Sobrien -u, --unix-byte-offsets report offsets as if CRs were not there (MSDOS)\n\ 118653477Sobrien\n\ 118755379Sobrien`egrep' means `grep -E'. `fgrep' means `grep -F'.\n\ 118855379SobrienWith no FILE, or when FILE is -, read standard input. If less than\n\ 118955379Sobrientwo FILEs given, assume -h. Exit status is 0 if match, 1 if no match,\n\ 119055379Sobrienand 2 if trouble.\n")); 119153477Sobrien printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n")); 119253477Sobrien } 119353477Sobrien exit (status); 119453451Speter} 119553451Speter 119655379Sobrien/* Set the matcher to M, reporting any conflicts. */ 119755379Sobrienstatic void 119856920Srusetmatcher (char const *m) 119955379Sobrien{ 120055379Sobrien if (matcher && strcmp (matcher, m) != 0) 1201131557Stjr error (2, 0, _("conflicting matchers specified")); 120255379Sobrien matcher = m; 120355379Sobrien} 120455379Sobrien 120553451Speter/* Go through the matchers vector and look for the specified matcher. 120653451Speter If we find it, install it in compile and execute, and return 1. */ 120753477Sobrienstatic int 120856920Sruinstall_matcher (char const *name) 120953451Speter{ 121053451Speter int i; 1211131557Stjr#if defined(HAVE_SETRLIMIT) 121253477Sobrien struct rlimit rlim; 121353477Sobrien#endif 121453451Speter 1215131557Stjr for (i = 0; matchers[i].compile; i++) 121653477Sobrien if (strcmp (name, matchers[i].name) == 0) 121753451Speter { 121853451Speter compile = matchers[i].compile; 121953451Speter execute = matchers[i].execute; 1220131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK) 122153477Sobrien /* I think every platform needs to do this, so that regex.c 122253477Sobrien doesn't oveflow the stack. The default value of 122353477Sobrien `re_max_failures' is too large for some platforms: it needs 122453477Sobrien more than 3MB-large stack. 122553477Sobrien 122653477Sobrien The test for HAVE_SETRLIMIT should go into `configure'. */ 122753477Sobrien if (!getrlimit (RLIMIT_STACK, &rlim)) 122853477Sobrien { 122953477Sobrien long newlim; 123053477Sobrien extern long int re_max_failures; /* from regex.c */ 123153477Sobrien 123253477Sobrien /* Approximate the amount regex.c needs, plus some more. */ 123353477Sobrien newlim = re_max_failures * 2 * 20 * sizeof (char *); 123453477Sobrien if (newlim > rlim.rlim_max) 123553477Sobrien { 123653477Sobrien newlim = rlim.rlim_max; 123753477Sobrien re_max_failures = newlim / (2 * 20 * sizeof (char *)); 123853477Sobrien } 123953477Sobrien if (rlim.rlim_cur < newlim) 1240131557Stjr { 1241131557Stjr rlim.rlim_cur = newlim; 1242131557Stjr setrlimit (RLIMIT_STACK, &rlim); 1243131557Stjr } 124453477Sobrien } 124553477Sobrien#endif 124653451Speter return 1; 124753451Speter } 124853451Speter return 0; 124953451Speter} 125053451Speter 125153705Sobrien/* Find the white-space-separated options specified by OPTIONS, and 125253705Sobrien using BUF to store copies of these options, set ARGV[0], ARGV[1], 125353705Sobrien etc. to the option copies. Return the number N of options found. 125453705Sobrien Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0] 125553705Sobrien etc. Backslash can be used to escape whitespace (and backslashes). */ 125653705Sobrienstatic int 125756920Sruprepend_args (char const *options, char *buf, char **argv) 125853705Sobrien{ 125953705Sobrien char const *o = options; 126053705Sobrien char *b = buf; 126153705Sobrien int n = 0; 126253705Sobrien 126353705Sobrien for (;;) 126453705Sobrien { 126553705Sobrien while (ISSPACE ((unsigned char) *o)) 126653705Sobrien o++; 126753705Sobrien if (!*o) 126853705Sobrien return n; 126953705Sobrien if (argv) 127053705Sobrien argv[n] = b; 127153705Sobrien n++; 127253705Sobrien 127353705Sobrien do 127453705Sobrien if ((*b++ = *o++) == '\\' && *o) 127553705Sobrien b[-1] = *o++; 127653705Sobrien while (*o && ! ISSPACE ((unsigned char) *o)); 127753705Sobrien 127853705Sobrien *b++ = '\0'; 127953705Sobrien } 128053705Sobrien} 128153705Sobrien 128253705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument 128353705Sobrien vector of a main program with argument count *PARGC and argument 128453705Sobrien vector *PARGV. */ 128553705Sobrienstatic void 128656920Sruprepend_default_options (char const *options, int *pargc, char ***pargv) 128753705Sobrien{ 128853705Sobrien if (options) 128953705Sobrien { 129053705Sobrien char *buf = xmalloc (strlen (options) + 1); 129153705Sobrien int prepended = prepend_args (options, buf, (char **) NULL); 129253705Sobrien int argc = *pargc; 129353705Sobrien char * const *argv = *pargv; 129453705Sobrien char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); 129553705Sobrien *pargc = prepended + argc; 129653705Sobrien *pargv = pp; 129753705Sobrien *pp++ = *argv++; 129853705Sobrien pp += prepend_args (options, buf, pp); 129953705Sobrien while ((*pp++ = *argv++)) 130053705Sobrien continue; 130153705Sobrien } 130253705Sobrien} 130353705Sobrien 1304131557Stjr/* Get the next non-digit option from ARGC and ARGV. 1305131557Stjr Return -1 if there are no more options. 1306131557Stjr Process any digit options that were encountered on the way, 1307131557Stjr and store the resulting integer into *DEFAULT_CONTEXT. */ 1308131557Stjrstatic int 1309131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context) 1310131557Stjr{ 1311131557Stjr int opt; 1312131557Stjr char buf[sizeof (uintmax_t) * CHAR_BIT + 4]; 1313131557Stjr char *p = buf; 1314131557Stjr 1315131557Stjr /* Set buf[0] to anything but '0', for the leading-zero test below. */ 1316131557Stjr buf[0] = '\0'; 1317131557Stjr 1318131557Stjr while (opt = getopt_long (argc, argv, short_options, long_options, NULL), 1319131557Stjr '0' <= opt && opt <= '9') 1320131557Stjr { 1321131557Stjr /* Suppress trivial leading zeros, to avoid incorrect 1322131557Stjr diagnostic on strings like 00000000000. */ 1323131557Stjr p -= buf[0] == '0'; 1324131557Stjr 1325131557Stjr *p++ = opt; 1326131557Stjr if (p == buf + sizeof buf - 4) 1327131557Stjr { 1328131557Stjr /* Too many digits. Append "..." to make context_length_arg 1329131557Stjr complain about "X...", where X contains the digits seen 1330131557Stjr so far. */ 1331131557Stjr strcpy (p, "..."); 1332131557Stjr p += 3; 1333131557Stjr break; 1334131557Stjr } 1335131557Stjr } 1336131557Stjr if (p != buf) 1337131557Stjr { 1338131557Stjr *p = '\0'; 1339131557Stjr context_length_arg (buf, default_context); 1340131557Stjr } 1341131557Stjr 1342131557Stjr return opt; 1343131557Stjr} 1344131557Stjr 134553451Speterint 134656920Srumain (int argc, char **argv) 134753451Speter{ 134853451Speter char *keys; 1349250937Spfg size_t cc, keycc, oldcc, keyalloc; 135053477Sobrien int with_filenames; 1351250937Spfg int opt, status; 135256920Sru int default_context; 135353451Speter FILE *fp; 135453451Speter extern char *optarg; 135553451Speter extern int optind; 135653477Sobrien 135753477Sobrien initialize_main (&argc, &argv); 1358131557Stjr program_name = argv[0]; 1359131557Stjr if (program_name && strrchr (program_name, '/')) 1360131557Stjr program_name = strrchr (program_name, '/') + 1; 136153477Sobrien 1362151534Sjkim if (program_name[0] == 'b' && program_name[1] == 'z') { 1363151527Sjkim BZflag = 1; 1364151527Sjkim program_name += 2; 1365151527Sjkim } 136653477Sobrien#if HAVE_LIBZ > 0 1367151534Sjkim else if (program_name[0] == 'z') { 136853477Sobrien Zflag = 1; 1369131557Stjr ++program_name; 137053477Sobrien } 137153451Speter#endif 137253451Speter 137353477Sobrien#if defined(__MSDOS__) || defined(_WIN32) 137453477Sobrien /* DOS and MS-Windows use backslashes as directory separators, and usually 137553477Sobrien have an .exe suffix. They also have case-insensitive filesystems. */ 1376131557Stjr if (program_name) 137753477Sobrien { 1378131557Stjr char *p = program_name; 137953477Sobrien char *bslash = strrchr (argv[0], '\\'); 138053477Sobrien 1381131557Stjr if (bslash && bslash >= program_name) /* for mixed forward/backslash case */ 1382131557Stjr program_name = bslash + 1; 1383131557Stjr else if (program_name == argv[0] 138453477Sobrien && argv[0][0] && argv[0][1] == ':') /* "c:progname" */ 1385131557Stjr program_name = argv[0] + 2; 138653477Sobrien 138753477Sobrien /* Collapse the letter-case, so `strcmp' could be used hence. */ 138853477Sobrien for ( ; *p; p++) 138953477Sobrien if (*p >= 'A' && *p <= 'Z') 139053477Sobrien *p += 'a' - 'A'; 139153477Sobrien 139253477Sobrien /* Remove the .exe extension, if any. */ 1393131557Stjr if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0) 139453477Sobrien *p = '\0'; 139553477Sobrien } 139653451Speter#endif 139753451Speter 139853451Speter keys = NULL; 139953451Speter keycc = 0; 140053477Sobrien with_filenames = 0; 140155379Sobrien eolbyte = '\n'; 140255379Sobrien filename_mask = ~0; 140353477Sobrien 1404131557Stjr max_count = TYPE_MAXIMUM (off_t); 1405131557Stjr 140653477Sobrien /* The value -1 means to use DEFAULT_CONTEXT. */ 140753477Sobrien out_after = out_before = -1; 140853477Sobrien /* Default before/after context: chaged by -C/-NUM options */ 140953477Sobrien default_context = 0; 1410131557Stjr /* Changed by -o option */ 1411131557Stjr only_matching = 0; 141253477Sobrien 1413131557Stjr /* Internationalization. */ 1414131557Stjr#if defined(HAVE_SETLOCALE) 141553477Sobrien setlocale (LC_ALL, ""); 141653451Speter#endif 1417131557Stjr#if defined(ENABLE_NLS) 141853477Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 141953477Sobrien textdomain (PACKAGE); 142053451Speter#endif 142153451Speter 1422131557Stjr atexit (close_stdout); 1423131557Stjr 142453705Sobrien prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv); 142553705Sobrien 1426131557Stjr while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1) 142753451Speter switch (opt) 142853451Speter { 142953451Speter case 'A': 1430131557Stjr context_length_arg (optarg, &out_after); 143153451Speter break; 1432131557Stjr 143353451Speter case 'B': 1434131557Stjr context_length_arg (optarg, &out_before); 143553451Speter break; 1436131557Stjr 143753451Speter case 'C': 143853477Sobrien /* Set output match context, but let any explicit leading or 143953477Sobrien trailing amount specified with -A or -B stand. */ 1440131557Stjr context_length_arg (optarg, &default_context); 1441131557Stjr break; 1442131557Stjr 1443131557Stjr case 'D': 1444131557Stjr if (strcmp (optarg, "read") == 0) 1445131557Stjr devices = READ_DEVICES; 1446131557Stjr else if (strcmp (optarg, "skip") == 0) 1447131557Stjr devices = SKIP_DEVICES; 144853477Sobrien else 1449131557Stjr error (2, 0, _("unknown devices method")); 145053451Speter break; 1451131557Stjr 145253451Speter case 'E': 145355379Sobrien setmatcher ("egrep"); 145453451Speter break; 1455131557Stjr 145653451Speter case 'F': 145755379Sobrien setmatcher ("fgrep"); 145853451Speter break; 1459131557Stjr 1460131557Stjr case 'P': 1461131557Stjr setmatcher ("perl"); 1462131557Stjr break; 1463131557Stjr 146453451Speter case 'G': 146555379Sobrien setmatcher ("grep"); 146653451Speter break; 1467131557Stjr 146853477Sobrien case 'H': 146953477Sobrien with_filenames = 1; 147053477Sobrien break; 1471131557Stjr 147256920Sru case 'I': 147356920Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 147456920Sru break; 1475103372Sobrien case 'J': 1476104555Sobrien if (Zflag) 1477104555Sobrien { 1478104555Sobrien printf (_("Cannot mix -Z and -J.\n")); 1479104555Sobrien usage (2); 1480104555Sobrien } 1481103372Sobrien BZflag = 1; 1482103372Sobrien break; 1483131557Stjr 148455379Sobrien case 'U': 1485131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 148653477Sobrien dos_use_file_type = DOS_BINARY; 148755379Sobrien#endif 148853477Sobrien break; 1489131557Stjr 149053477Sobrien case 'u': 1491131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 149253477Sobrien dos_report_unix_offset = 1; 149355379Sobrien#endif 149453477Sobrien break; 1495131557Stjr 149653451Speter case 'V': 149753477Sobrien show_version = 1; 149853451Speter break; 1499131557Stjr 150053451Speter case 'X': 150155379Sobrien setmatcher (optarg); 150253451Speter break; 1503131557Stjr 150453451Speter case 'a': 150556233Sru binary_files = TEXT_BINARY_FILES; 150653451Speter break; 1507131557Stjr 150853451Speter case 'b': 150953451Speter out_byte = 1; 151053451Speter break; 1511131557Stjr 151253451Speter case 'c': 151353451Speter count_matches = 1; 151453451Speter break; 1515131557Stjr 151653477Sobrien case 'd': 151753477Sobrien if (strcmp (optarg, "read") == 0) 151853477Sobrien directories = READ_DIRECTORIES; 151953477Sobrien else if (strcmp (optarg, "skip") == 0) 152053477Sobrien directories = SKIP_DIRECTORIES; 152153477Sobrien else if (strcmp (optarg, "recurse") == 0) 152253477Sobrien directories = RECURSE_DIRECTORIES; 152353477Sobrien else 1524131557Stjr error (2, 0, _("unknown directories method")); 152553477Sobrien break; 1526131557Stjr 152753451Speter case 'e': 152853477Sobrien cc = strlen (optarg); 152953477Sobrien keys = xrealloc (keys, keycc + cc + 1); 153053477Sobrien strcpy (&keys[keycc], optarg); 153153451Speter keycc += cc; 153253477Sobrien keys[keycc++] = '\n'; 153353451Speter break; 1534131557Stjr 153553451Speter case 'f': 153653477Sobrien fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin; 153753451Speter if (!fp) 1538131557Stjr error (2, errno, "%s", optarg); 153953477Sobrien for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2) 154053451Speter ; 154153477Sobrien keys = xrealloc (keys, keyalloc); 154253451Speter oldcc = keycc; 154353477Sobrien while (!feof (fp) 154453477Sobrien && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0) 154553451Speter { 154653451Speter keycc += cc; 154753477Sobrien if (keycc == keyalloc - 1) 154853477Sobrien keys = xrealloc (keys, keyalloc *= 2); 154953451Speter } 155053451Speter if (fp != stdin) 155153451Speter fclose(fp); 155253477Sobrien /* Append final newline if file ended in non-newline. */ 155353477Sobrien if (oldcc != keycc && keys[keycc - 1] != '\n') 155453477Sobrien keys[keycc++] = '\n'; 155553451Speter break; 1556131557Stjr 155753451Speter case 'h': 155853451Speter no_filenames = 1; 155953451Speter break; 1560131557Stjr 156153451Speter case 'i': 156253451Speter case 'y': /* For old-timers . . . */ 156353451Speter match_icase = 1; 156453451Speter break; 1565131557Stjr 156653451Speter case 'L': 156753451Speter /* Like -l, except list files that don't contain matches. 156853451Speter Inspired by the same option in Hume's gre. */ 156953451Speter list_files = -1; 157053451Speter break; 1571131557Stjr 157253451Speter case 'l': 157353451Speter list_files = 1; 157453451Speter break; 1575131557Stjr 1576131557Stjr case 'm': 1577131557Stjr { 1578131557Stjr uintmax_t value; 1579131557Stjr switch (xstrtoumax (optarg, 0, 10, &value, "")) 1580131557Stjr { 1581131557Stjr case LONGINT_OK: 1582131557Stjr max_count = value; 1583131557Stjr if (0 <= max_count && max_count == value) 1584131557Stjr break; 1585131557Stjr /* Fall through. */ 1586131557Stjr case LONGINT_OVERFLOW: 1587131557Stjr max_count = TYPE_MAXIMUM (off_t); 1588131557Stjr break; 1589131557Stjr 1590131557Stjr default: 1591131557Stjr error (2, 0, _("invalid max count")); 1592131557Stjr } 1593131557Stjr } 1594131557Stjr break; 1595131557Stjr 159653451Speter case 'n': 159753451Speter out_line = 1; 159853451Speter break; 1599131557Stjr 1600131557Stjr case 'o': 1601131557Stjr only_matching = 1; 1602131557Stjr break; 1603131557Stjr 160453451Speter case 'q': 1605131557Stjr exit_on_match = 1; 1606131557Stjr close_stdout_set_status(0); 160753451Speter break; 1608131557Stjr 160953478Sobrien case 'R': 161053477Sobrien case 'r': 161153477Sobrien directories = RECURSE_DIRECTORIES; 161253477Sobrien break; 1613131557Stjr 161453451Speter case 's': 161553451Speter suppress_errors = 1; 161653451Speter break; 1617131557Stjr 161853451Speter case 'v': 161953451Speter out_invert = 1; 162053451Speter break; 1621131557Stjr 162253451Speter case 'w': 162353451Speter match_words = 1; 162453451Speter break; 1625131557Stjr 162653451Speter case 'x': 162753451Speter match_lines = 1; 162853451Speter break; 1629131557Stjr 163055379Sobrien case 'Z': 163155379Sobrien#if HAVE_LIBZ > 0 1632104555Sobrien if (BZflag) 1633104555Sobrien { 1634104555Sobrien printf (_("Cannot mix -J and -Z.\n")); 1635104555Sobrien usage (2); 1636104555Sobrien } 163755379Sobrien Zflag = 1; 163855379Sobrien#else 163955379Sobrien filename_mask = 0; 164055379Sobrien#endif 164155379Sobrien break; 1642131557Stjr 164355379Sobrien case 'z': 164455379Sobrien eolbyte = '\0'; 164555379Sobrien break; 1646131557Stjr 164756233Sru case BINARY_FILES_OPTION: 164856233Sru if (strcmp (optarg, "binary") == 0) 164956233Sru binary_files = BINARY_BINARY_FILES; 165056233Sru else if (strcmp (optarg, "text") == 0) 165156233Sru binary_files = TEXT_BINARY_FILES; 165256233Sru else if (strcmp (optarg, "without-match") == 0) 165356233Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 165456233Sru else 1655131557Stjr error (2, 0, _("unknown binary-files type")); 165656233Sru break; 1657131557Stjr 1658131557Stjr case COLOR_OPTION: 1659131557Stjr if(optarg) { 1660131557Stjr if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") || 1661131557Stjr !strcasecmp(optarg, "force")) 1662131557Stjr color_option = 1; 1663131557Stjr else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") || 1664131557Stjr !strcasecmp(optarg, "none")) 1665131557Stjr color_option = 0; 1666131557Stjr else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") || 1667131557Stjr !strcasecmp(optarg, "if-tty")) 1668131557Stjr color_option = 2; 1669131557Stjr else 1670131557Stjr show_help = 1; 1671131557Stjr } else 1672131557Stjr color_option = 2; 1673131557Stjr if(color_option == 2) { 1674131557Stjr if(isatty(STDOUT_FILENO) && getenv("TERM") && 1675131557Stjr strcmp(getenv("TERM"), "dumb")) 1676131557Stjr color_option = 1; 1677131557Stjr else 1678131557Stjr color_option = 0; 1679131557Stjr } 1680131557Stjr break; 1681131557Stjr 1682131557Stjr case EXCLUDE_OPTION: 1683131557Stjr if (!excluded_patterns) 1684131557Stjr excluded_patterns = new_exclude (); 1685131557Stjr add_exclude (excluded_patterns, optarg); 1686131557Stjr break; 1687131557Stjr 1688131557Stjr case EXCLUDE_FROM_OPTION: 1689131557Stjr if (!excluded_patterns) 1690131557Stjr excluded_patterns = new_exclude (); 1691131557Stjr if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n') 1692131557Stjr != 0) 1693131557Stjr { 1694131557Stjr error (2, errno, "%s", optarg); 1695131557Stjr } 1696131557Stjr break; 1697131557Stjr 1698131557Stjr case INCLUDE_OPTION: 1699131557Stjr if (!included_patterns) 1700131557Stjr included_patterns = new_exclude (); 1701131557Stjr add_exclude (included_patterns, optarg); 1702131557Stjr break; 1703131557Stjr 1704131557Stjr case LINE_BUFFERED_OPTION: 1705131557Stjr line_buffered = 1; 1706131557Stjr break; 1707131557Stjr 1708131557Stjr case LABEL_OPTION: 1709131557Stjr label = optarg; 1710131557Stjr break; 1711131557Stjr 171253477Sobrien case 0: 171353477Sobrien /* long options */ 171453477Sobrien break; 1715131557Stjr 171653451Speter default: 171753477Sobrien usage (2); 171853451Speter break; 1719131557Stjr 172053451Speter } 172153451Speter 1722131557Stjr /* POSIX.2 says that -q overrides -l, which in turn overrides the 1723131557Stjr other output options. */ 1724131557Stjr if (exit_on_match) 1725131557Stjr list_files = 0; 1726131557Stjr if (exit_on_match | list_files) 1727131557Stjr { 1728131557Stjr count_matches = 0; 1729131557Stjr done_on_match = 1; 1730131557Stjr } 1731131557Stjr out_quiet = count_matches | done_on_match; 1732131557Stjr 173353477Sobrien if (out_after < 0) 173453477Sobrien out_after = default_context; 173553477Sobrien if (out_before < 0) 173653477Sobrien out_before = default_context; 173753477Sobrien 1738131557Stjr if (color_option) 1739131557Stjr { 1740131557Stjr char *userval = getenv ("GREP_COLOR"); 1741131557Stjr if (userval != NULL && *userval != '\0') 1742131557Stjr grep_color = userval; 1743131557Stjr } 1744131557Stjr 174555379Sobrien if (! matcher) 1746131557Stjr matcher = program_name; 174755379Sobrien 174853477Sobrien if (show_version) 174953477Sobrien { 175055379Sobrien printf (_("%s (GNU grep) %s\n"), matcher, VERSION); 175153477Sobrien printf ("\n"); 175253477Sobrien printf (_("\ 1753131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n")); 175453477Sobrien printf (_("\ 175553477SobrienThis is free software; see the source for copying conditions. There is NO\n\ 175653477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")); 175753477Sobrien printf ("\n"); 175853477Sobrien exit (0); 175953477Sobrien } 176053477Sobrien 176153477Sobrien if (show_help) 176253477Sobrien usage (0); 176353477Sobrien 176453477Sobrien if (keys) 176553477Sobrien { 176653477Sobrien if (keycc == 0) 1767131557Stjr { 1768131557Stjr /* No keys were specified (e.g. -f /dev/null). Match nothing. */ 1769131557Stjr out_invert ^= 1; 1770131557Stjr match_lines = match_words = 0; 1771131557Stjr } 177253477Sobrien else 177353477Sobrien /* Strip trailing newline. */ 177453477Sobrien --keycc; 177553477Sobrien } 177653477Sobrien else 177753451Speter if (optind < argc) 177853451Speter { 177953451Speter keys = argv[optind++]; 178053477Sobrien keycc = strlen (keys); 178153451Speter } 178253451Speter else 178353477Sobrien usage (2); 178453451Speter 178555379Sobrien if (!install_matcher (matcher) && !install_matcher ("default")) 178653477Sobrien abort (); 178753451Speter 1788131564Stjr#ifdef MBS_SUPPORT 1789131564Stjr if (MB_CUR_MAX != 1 && match_icase) 1790131564Stjr { 1791131564Stjr wchar_t wc; 1792131564Stjr mbstate_t cur_state, prev_state; 1793131564Stjr int i, len = strlen(keys); 1794131564Stjr 1795131564Stjr memset(&cur_state, 0, sizeof(mbstate_t)); 1796131564Stjr for (i = 0; i <= len ;) 1797131564Stjr { 1798131564Stjr size_t mbclen; 1799131564Stjr mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state); 1800131564Stjr if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0) 1801131564Stjr { 1802131564Stjr /* An invalid sequence, or a truncated multibyte character. 1803131564Stjr We treat it as a singlebyte character. */ 1804131564Stjr mbclen = 1; 1805131564Stjr } 1806131564Stjr else 1807131564Stjr { 1808131564Stjr if (iswupper((wint_t)wc)) 1809131564Stjr { 1810131564Stjr wc = towlower((wint_t)wc); 1811131564Stjr wcrtomb(keys + i, wc, &cur_state); 1812131564Stjr } 1813131564Stjr } 1814131564Stjr i += mbclen; 1815131564Stjr } 1816131564Stjr } 1817131564Stjr#endif /* MBS_SUPPORT */ 1818131564Stjr 181953451Speter (*compile)(keys, keycc); 182053451Speter 182153477Sobrien if ((argc - optind > 1 && !no_filenames) || with_filenames) 182253451Speter out_file = 1; 182353451Speter 1824131557Stjr#ifdef SET_BINARY 182553477Sobrien /* Output is set to binary mode because we shouldn't convert 182653477Sobrien NL to CR-LF pairs, especially when grepping binary files. */ 182753477Sobrien if (!isatty (1)) 182853477Sobrien SET_BINARY (1); 182953451Speter#endif 183053451Speter 1831131557Stjr if (max_count == 0) 1832131557Stjr exit (1); 183353451Speter 183453451Speter if (optind < argc) 183553451Speter { 183653477Sobrien status = 1; 183753477Sobrien do 183853451Speter { 183953477Sobrien char *file = argv[optind]; 1840131557Stjr if ((included_patterns || excluded_patterns) 1841131557Stjr && !isdir (file)) 1842131557Stjr { 1843131557Stjr if (included_patterns && 1844131557Stjr ! excluded_filename (included_patterns, file, 0)) 1845131557Stjr continue; 1846131557Stjr if (excluded_patterns && 1847131557Stjr excluded_filename (excluded_patterns, file, 0)) 1848131557Stjr continue; 1849131557Stjr } 185053477Sobrien status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file, 185153477Sobrien &stats_base); 185253451Speter } 185353477Sobrien while ( ++optind < argc); 185453451Speter } 185553477Sobrien else 185653477Sobrien status = grepfile ((char *) NULL, &stats_base); 185753451Speter 1858131557Stjr /* We register via atexit() to test stdout. */ 185953477Sobrien exit (errseen ? 2 : status); 186053451Speter} 1861131557Stjr/* vim:set shiftwidth=2: */ 1862