grep.c revision 131557
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: head/gnu/usr.bin/grep/grep.c 131557 2004-07-04 10:02:03Z tjr $ */ 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 3653477Sobrien#include <stdio.h> 3753477Sobrien#include "system.h" 3853477Sobrien#include "getopt.h" 3953451Speter#include "getpagesize.h" 4053451Speter#include "grep.h" 4153477Sobrien#include "savedir.h" 42131557Stjr#include "xstrtol.h" 43131557Stjr#include "xalloc.h" 44131557Stjr#include "error.h" 45131557Stjr#include "exclude.h" 46131557Stjr#include "closeout.h" 4753451Speter 4853451Speter#undef MAX 4953451Speter#define MAX(A,B) ((A) > (B) ? (A) : (B)) 5053451Speter 5153477Sobrienstruct stats 5253477Sobrien{ 53131557Stjr struct stats const *parent; 5453477Sobrien struct stat stat; 5553477Sobrien}; 5653451Speter 5753477Sobrien/* base of chain of stat buffers, used to detect directory loops */ 5853477Sobrienstatic struct stats stats_base; 5953451Speter 6053477Sobrien/* if non-zero, display usage information and exit */ 6153477Sobrienstatic int show_help; 6253451Speter 6353477Sobrien/* If non-zero, print the version on standard output and exit. */ 6453477Sobrienstatic int show_version; 6553451Speter 66131557Stjr/* If nonzero, suppress diagnostics for nonexistent or unreadable files. */ 67131557Stjrstatic int suppress_errors; 68131557Stjr 6955379Sobrien/* If nonzero, use mmap if possible. */ 7055379Sobrienstatic int mmap_option; 7155379Sobrien 7255404Sru/* If zero, output nulls after filenames. */ 7355404Srustatic int filename_mask; 7455404Sru 75131557Stjr/* If nonzero, use grep_color marker. */ 76131557Stjrstatic int color_option; 77131557Stjr 78131557Stjr/* If nonzero, show only the part of a line matching the expression. */ 79131557Stjrstatic int only_matching; 80131557Stjr 81131557Stjr/* The color string used. The user can overwrite it using the environment 82131557Stjr variable GREP_COLOR. The default is to print red. */ 83131557Stjrstatic const char *grep_color = "01;31"; 84131557Stjr 85131557Stjrstatic struct exclude *excluded_patterns; 86131557Stjrstatic struct exclude *included_patterns; 8755379Sobrien/* Short options. */ 8855379Sobrienstatic char const short_options[] = 89131557Stjr"0123456789A:B:C:D:EFGHIJPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz"; 9055379Sobrien 9156233Sru/* Non-boolean long options that have no corresponding short equivalents. */ 9256233Sruenum 9356233Sru{ 94131557Stjr BINARY_FILES_OPTION = CHAR_MAX + 1, 95131557Stjr COLOR_OPTION, 96131557Stjr INCLUDE_OPTION, 97131557Stjr EXCLUDE_OPTION, 98131557Stjr EXCLUDE_FROM_OPTION, 99131557Stjr LINE_BUFFERED_OPTION, 100131557Stjr LABEL_OPTION 10156233Sru}; 10256233Sru 10353477Sobrien/* Long options equivalences. */ 104131557Stjrstatic struct option const long_options[] = 10553477Sobrien{ 10653477Sobrien {"after-context", required_argument, NULL, 'A'}, 10753477Sobrien {"basic-regexp", no_argument, NULL, 'G'}, 10853477Sobrien {"before-context", required_argument, NULL, 'B'}, 10956233Sru {"binary-files", required_argument, NULL, BINARY_FILES_OPTION}, 11053477Sobrien {"byte-offset", no_argument, NULL, 'b'}, 111131557Stjr {"context", required_argument, NULL, 'C'}, 112131557Stjr {"color", optional_argument, NULL, COLOR_OPTION}, 113131557Stjr {"colour", optional_argument, NULL, COLOR_OPTION}, 11453477Sobrien {"count", no_argument, NULL, 'c'}, 115131557Stjr {"devices", required_argument, NULL, 'D'}, 11653477Sobrien {"directories", required_argument, NULL, 'd'}, 11753477Sobrien {"extended-regexp", no_argument, NULL, 'E'}, 118131557Stjr {"exclude", required_argument, NULL, EXCLUDE_OPTION}, 119131557Stjr {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION}, 12053477Sobrien {"file", required_argument, NULL, 'f'}, 12153477Sobrien {"files-with-matches", no_argument, NULL, 'l'}, 12253477Sobrien {"files-without-match", no_argument, NULL, 'L'}, 12353477Sobrien {"fixed-regexp", no_argument, NULL, 'F'}, 12453477Sobrien {"fixed-strings", no_argument, NULL, 'F'}, 12553477Sobrien {"help", no_argument, &show_help, 1}, 126131557Stjr {"include", required_argument, NULL, INCLUDE_OPTION}, 12753477Sobrien {"ignore-case", no_argument, NULL, 'i'}, 128131557Stjr {"label", required_argument, NULL, LABEL_OPTION}, 129131557Stjr {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION}, 13053477Sobrien {"line-number", no_argument, NULL, 'n'}, 13153477Sobrien {"line-regexp", no_argument, NULL, 'x'}, 132131557Stjr {"max-count", required_argument, NULL, 'm'}, 13355379Sobrien {"mmap", no_argument, &mmap_option, 1}, 13453477Sobrien {"no-filename", no_argument, NULL, 'h'}, 13553477Sobrien {"no-messages", no_argument, NULL, 's'}, 136103372Sobrien {"bz2decompress", no_argument, NULL, 'J'}, 13755379Sobrien#if HAVE_LIBZ > 0 13855404Sru {"decompress", no_argument, NULL, 'Z'}, 13955404Sru {"null", no_argument, &filename_mask, 0}, 14055379Sobrien#else 14155379Sobrien {"null", no_argument, NULL, 'Z'}, 14255379Sobrien#endif 14355379Sobrien {"null-data", no_argument, NULL, 'z'}, 144131557Stjr {"only-matching", no_argument, NULL, 'o'}, 145131557Stjr {"perl-regexp", no_argument, NULL, 'P'}, 14653477Sobrien {"quiet", no_argument, NULL, 'q'}, 14753477Sobrien {"recursive", no_argument, NULL, 'r'}, 148131557Stjr {"recursive", no_argument, NULL, 'R'}, 14953477Sobrien {"regexp", required_argument, NULL, 'e'}, 15055379Sobrien {"invert-match", no_argument, NULL, 'v'}, 15153477Sobrien {"silent", no_argument, NULL, 'q'}, 15253477Sobrien {"text", no_argument, NULL, 'a'}, 15353477Sobrien {"binary", no_argument, NULL, 'U'}, 15453477Sobrien {"unix-byte-offsets", no_argument, NULL, 'u'}, 15553477Sobrien {"version", no_argument, NULL, 'V'}, 15653477Sobrien {"with-filename", no_argument, NULL, 'H'}, 15753477Sobrien {"word-regexp", no_argument, NULL, 'w'}, 15853477Sobrien {0, 0, 0, 0} 15953477Sobrien}; 16053451Speter 16153451Speter/* Define flags declared in grep.h. */ 16253451Speterint match_icase; 16353451Speterint match_words; 16453451Speterint match_lines; 16555379Sobrienunsigned char eolbyte; 16653451Speter 16753451Speter/* For error messages. */ 168131557Stjr/* The name the program was run with, stripped of any leading path. */ 169131557Stjrchar *program_name; 17053477Sobrienstatic char const *filename; 17153451Speterstatic int errseen; 17253451Speter 17353477Sobrien/* How to handle directories. */ 17453477Sobrienstatic enum 17553477Sobrien { 17653477Sobrien READ_DIRECTORIES, 17753477Sobrien RECURSE_DIRECTORIES, 17853477Sobrien SKIP_DIRECTORIES 179131557Stjr } directories = READ_DIRECTORIES; 18053477Sobrien 181131557Stjr/* How to handle devices. */ 182131557Stjrstatic enum 183131557Stjr { 184131557Stjr READ_DEVICES, 185131557Stjr SKIP_DEVICES 186131557Stjr } devices = READ_DEVICES; 187131557Stjr 188131557Stjrstatic int grepdir PARAMS ((char const *, struct stats const *)); 189131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 19053477Sobrienstatic inline int undossify_input PARAMS ((register char *, size_t)); 19153477Sobrien#endif 19253477Sobrien 19353477Sobrien/* Functions we'll use to search. */ 194131557Stjrstatic void (*compile) PARAMS ((char const *, size_t)); 195131557Stjrstatic size_t (*execute) PARAMS ((char const *, size_t, size_t *, int)); 19653477Sobrien 197131557Stjr/* Like error, but suppress the diagnostic if requested. */ 19853451Speterstatic void 199131557Stjrsuppressible_error (char const *mesg, int errnum) 20053451Speter{ 201131557Stjr if (! suppress_errors) 202131557Stjr error (0, errnum, "%s", mesg); 20353451Speter errseen = 1; 20453451Speter} 20553451Speter 20653477Sobrien/* Convert STR to a positive integer, storing the result in *OUT. 207131557Stjr STR must be a valid context length argument; report an error if it 208131557Stjr isn't. */ 209131557Stjrstatic void 210131557Stjrcontext_length_arg (char const *str, int *out) 21153477Sobrien{ 212131557Stjr uintmax_t value; 213131557Stjr if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK 214131557Stjr && 0 <= (*out = value) 215131557Stjr && *out == value)) 216131557Stjr { 217131557Stjr error (2, 0, "%s: %s\n", str, _("invalid context length argument")); 218131557Stjr } 21953477Sobrien} 22053477Sobrien 22153477Sobrien 22253451Speter/* Hairy buffering mechanism for grep. The intent is to keep 22353451Speter all reads aligned on a page boundary and multiples of the 224131557Stjr page size, unless a read yields a partial page. */ 22553451Speter 22653451Speterstatic char *buffer; /* Base of buffer. */ 227131557Stjrstatic size_t bufalloc; /* Allocated buffer size, counting slop. */ 228131557Stjr#define INITIAL_BUFSIZE 32768 /* Initial buffer size, not counting slop. */ 22953451Speterstatic int bufdesc; /* File descriptor. */ 23053451Speterstatic char *bufbeg; /* Beginning of user-visible stuff. */ 23153451Speterstatic char *buflim; /* Limit of user-visible stuff. */ 23253477Sobrienstatic size_t pagesize; /* alignment of memory pages */ 23355379Sobrienstatic off_t bufoffset; /* Read offset; defined on regular files. */ 234131557Stjrstatic off_t after_last_match; /* Pointer after last matching line that 235131557Stjr would have been output if we were 236131557Stjr outputting characters. */ 23753451Speter 23853477Sobrien#if defined(HAVE_MMAP) 23955379Sobrienstatic int bufmapped; /* True if buffer is memory-mapped. */ 24053477Sobrienstatic off_t initial_bufoffset; /* Initial value of bufoffset. */ 241131557Stjr#else 242131557Stjr# define bufmapped 0 24353451Speter#endif 24453451Speter 245103372Sobrien#include <bzlib.h> 246103372Sobrienstatic BZFILE* bzbufdesc; /* libbz2 file handle. */ 247103372Sobrienstatic int BZflag; /* uncompress before searching. */ 24853451Speter#if HAVE_LIBZ > 0 24953451Speter#include <zlib.h> 25053477Sobrienstatic gzFile gzbufdesc; /* zlib file descriptor. */ 25153477Sobrienstatic int Zflag; /* uncompress before searching. */ 25253451Speter#endif 25353451Speter 25453477Sobrien/* Return VAL aligned to the next multiple of ALIGNMENT. VAL can be 25553477Sobrien an integer or a pointer. Both args must be free of side effects. */ 25653477Sobrien#define ALIGN_TO(val, alignment) \ 25753477Sobrien ((size_t) (val) % (alignment) == 0 \ 25853477Sobrien ? (val) \ 25953477Sobrien : (val) + ((alignment) - (size_t) (val) % (alignment))) 26053477Sobrien 26153477Sobrien/* Reset the buffer for a new file, returning zero if we should skip it. 26253477Sobrien Initialize on the first time through. */ 26353477Sobrienstatic int 26456920Srureset (int fd, char const *file, struct stats *stats) 26553451Speter{ 266131557Stjr if (! pagesize) 26753451Speter { 26853477Sobrien pagesize = getpagesize (); 269131557Stjr if (pagesize == 0 || 2 * pagesize + 1 <= pagesize) 27053477Sobrien abort (); 271131557Stjr bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1; 272131557Stjr buffer = xmalloc (bufalloc); 27353451Speter } 274103372Sobrien if (BZflag) 275103372Sobrien { 276103372Sobrien bzbufdesc = BZ2_bzdopen(fd, "r"); 277103372Sobrien if (bzbufdesc == NULL) 278131557Stjr error(2, 0, _("memory exhausted")); 279103372Sobrien } 28053451Speter#if HAVE_LIBZ > 0 28155379Sobrien if (Zflag) 28255379Sobrien { 28353451Speter gzbufdesc = gzdopen(fd, "r"); 28453477Sobrien if (gzbufdesc == NULL) 285131557Stjr error(2, 0, _("memory exhausted")); 28655379Sobrien } 28753451Speter#endif 28855379Sobrien 289131557Stjr bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize); 290131557Stjr bufbeg[-1] = eolbyte; 29153477Sobrien bufdesc = fd; 29253477Sobrien 29355379Sobrien if (fstat (fd, &stats->stat) != 0) 29455379Sobrien { 295131557Stjr error (0, errno, "fstat"); 29655379Sobrien return 0; 29755379Sobrien } 29853477Sobrien if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode)) 29953477Sobrien return 0; 300131557Stjr#ifndef DJGPP 301131557Stjr if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode))) 302131557Stjr#else 303131557Stjr if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode))) 304131557Stjr#endif 305131557Stjr return 0; 30653477Sobrien if ( 307103372Sobrien BZflag || 30853451Speter#if HAVE_LIBZ > 0 30953477Sobrien Zflag || 31053451Speter#endif 31155379Sobrien S_ISREG (stats->stat.st_mode)) 31255379Sobrien { 31355379Sobrien if (file) 31455379Sobrien bufoffset = 0; 31555379Sobrien else 31655379Sobrien { 31755379Sobrien bufoffset = lseek (fd, 0, SEEK_CUR); 31855379Sobrien if (bufoffset < 0) 31955379Sobrien { 320131557Stjr error (0, errno, "lseek"); 32155379Sobrien return 0; 32255379Sobrien } 32355379Sobrien } 324131557Stjr#if defined(HAVE_MMAP) 32555379Sobrien initial_bufoffset = bufoffset; 32655379Sobrien bufmapped = mmap_option && bufoffset % pagesize == 0; 32755379Sobrien#endif 32855379Sobrien } 32953451Speter else 33053451Speter { 331131557Stjr#if defined(HAVE_MMAP) 33255379Sobrien bufmapped = 0; 33355379Sobrien#endif 33453451Speter } 33553477Sobrien return 1; 33653451Speter} 33753451Speter 33853451Speter/* Read new stuff into the buffer, saving the specified 33953451Speter amount of old stuff. When we're done, 'bufbeg' points 34053451Speter to the beginning of the buffer contents, and 'buflim' 34155379Sobrien points just after the end. Return zero if there's an error. */ 34253451Speterstatic int 343131557Stjrfillbuf (size_t save, struct stats const *stats) 34453451Speter{ 34555379Sobrien size_t fillsize = 0; 34655379Sobrien int cc = 1; 347131557Stjr char *readbuf; 34855379Sobrien size_t readsize; 34953451Speter 350131557Stjr /* Offset from start of buffer to start of old stuff 35155379Sobrien that we want to save. */ 352131557Stjr size_t saved_offset = buflim - save - buffer; 35355379Sobrien 354131557Stjr if (pagesize <= buffer + bufalloc - buflim) 35553451Speter { 356131557Stjr readbuf = buflim; 357131557Stjr bufbeg = buflim - save; 358131557Stjr } 359131557Stjr else 360131557Stjr { 361131557Stjr size_t minsize = save + pagesize; 362131557Stjr size_t newsize; 36355379Sobrien size_t newalloc; 364131557Stjr char *newbuf; 36553477Sobrien 366131557Stjr /* Grow newsize until it is at least as great as minsize. */ 367131557Stjr for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2) 368131557Stjr if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2) 369131557Stjr xalloc_die (); 370131557Stjr 371131557Stjr /* Try not to allocate more memory than the file size indicates, 372131557Stjr as that might cause unnecessary memory exhaustion if the file 373131557Stjr is large. However, do not use the original file size as a 374131557Stjr heuristic if we've already read past the file end, as most 375131557Stjr likely the file is growing. */ 37655379Sobrien if (S_ISREG (stats->stat.st_mode)) 37755379Sobrien { 37855379Sobrien off_t to_be_read = stats->stat.st_size - bufoffset; 379131557Stjr off_t maxsize_off = save + to_be_read; 380131557Stjr if (0 <= to_be_read && to_be_read <= maxsize_off 381131557Stjr && maxsize_off == (size_t) maxsize_off 382131557Stjr && minsize <= (size_t) maxsize_off 383131557Stjr && (size_t) maxsize_off < newsize) 384131557Stjr newsize = maxsize_off; 38555379Sobrien } 38655379Sobrien 387131557Stjr /* Add enough room so that the buffer is aligned and has room 388131557Stjr for byte sentinels fore and aft. */ 389131557Stjr newalloc = newsize + pagesize + 1; 39055379Sobrien 391131557Stjr newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer; 392131557Stjr readbuf = ALIGN_TO (newbuf + 1 + save, pagesize); 393131557Stjr bufbeg = readbuf - save; 394131557Stjr memmove (bufbeg, buffer + saved_offset, save); 395131557Stjr bufbeg[-1] = eolbyte; 396131557Stjr if (newbuf != buffer) 39755379Sobrien { 398131557Stjr free (buffer); 399131557Stjr buffer = newbuf; 40055379Sobrien } 40153451Speter } 40253451Speter 403131557Stjr readsize = buffer + bufalloc - readbuf; 404131557Stjr readsize -= readsize % pagesize; 40555379Sobrien 40653477Sobrien#if defined(HAVE_MMAP) 40755379Sobrien if (bufmapped) 40853451Speter { 40955379Sobrien size_t mmapsize = readsize; 41055379Sobrien 41155379Sobrien /* Don't mmap past the end of the file; some hosts don't allow this. 41255379Sobrien Use `read' on the last page. */ 41355379Sobrien if (stats->stat.st_size - bufoffset < mmapsize) 41453451Speter { 41555379Sobrien mmapsize = stats->stat.st_size - bufoffset; 41655379Sobrien mmapsize -= mmapsize % pagesize; 41753451Speter } 41855379Sobrien 41955379Sobrien if (mmapsize 420131557Stjr && (mmap ((caddr_t) readbuf, mmapsize, 42155379Sobrien PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 42255379Sobrien bufdesc, bufoffset) 42355379Sobrien != (caddr_t) -1)) 42453451Speter { 42555379Sobrien /* Do not bother to use madvise with MADV_SEQUENTIAL or 42655379Sobrien MADV_WILLNEED on the mmapped memory. One might think it 42755379Sobrien would help, but it slows us down about 30% on SunOS 4.1. */ 42855379Sobrien fillsize = mmapsize; 42955379Sobrien } 43055379Sobrien else 43155379Sobrien { 43255379Sobrien /* Stop using mmap on this file. Synchronize the file 43355379Sobrien offset. Do not warn about mmap failures. On some hosts 43455379Sobrien (e.g. Solaris 2.5) mmap can fail merely because some 43555379Sobrien other process has an advisory read lock on the file. 43655379Sobrien There's no point alarming the user about this misfeature. */ 43753451Speter bufmapped = 0; 43855379Sobrien if (bufoffset != initial_bufoffset 43955379Sobrien && lseek (bufdesc, bufoffset, SEEK_SET) < 0) 44055379Sobrien { 441131557Stjr error (0, errno, "lseek"); 44255379Sobrien cc = 0; 44355379Sobrien } 44453451Speter } 44555379Sobrien } 44655379Sobrien#endif /*HAVE_MMAP*/ 44755379Sobrien 44855379Sobrien if (! fillsize) 44955379Sobrien { 45055379Sobrien ssize_t bytesread; 45155379Sobrien do 452104555Sobrien if (BZflag && bzbufdesc) 453103372Sobrien { 454104555Sobrien int bzerr; 455131557Stjr bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize); 456104555Sobrien 457104555Sobrien switch (bzerr) 458104555Sobrien { 459104555Sobrien case BZ_OK: 460104555Sobrien case BZ_STREAM_END: 461104555Sobrien /* ok */ 462104555Sobrien break; 463104555Sobrien case BZ_DATA_ERROR_MAGIC: 464104555Sobrien BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL; 465104555Sobrien lseek (bufdesc, 0, SEEK_SET); 466131557Stjr bytesread = read (bufdesc, readbuf, readsize); 467104555Sobrien break; 468104555Sobrien default: 469104555Sobrien bytesread = 0; 470104555Sobrien break; 471104555Sobrien } 472103372Sobrien } 473103372Sobrien else 47453451Speter#if HAVE_LIBZ > 0 47555379Sobrien if (Zflag) 476131557Stjr bytesread = gzread (gzbufdesc, readbuf, readsize); 47755379Sobrien else 47855379Sobrien#endif 479131557Stjr bytesread = read (bufdesc, readbuf, readsize); 48055379Sobrien while (bytesread < 0 && errno == EINTR); 48155379Sobrien if (bytesread < 0) 48255379Sobrien cc = 0; 48353477Sobrien else 48455379Sobrien fillsize = bytesread; 48553451Speter } 48655379Sobrien 48755379Sobrien bufoffset += fillsize; 488131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 48955379Sobrien if (fillsize) 490131557Stjr fillsize = undossify_input (readbuf, fillsize); 49153451Speter#endif 492131557Stjr buflim = readbuf + fillsize; 49353451Speter return cc; 49453451Speter} 49553451Speter 49653451Speter/* Flags controlling the style of output. */ 49756233Srustatic enum 498131557Stjr{ 499131557Stjr BINARY_BINARY_FILES, 500131557Stjr TEXT_BINARY_FILES, 501131557Stjr WITHOUT_MATCH_BINARY_FILES 502131557Stjr} binary_files; /* How to handle binary files. */ 503131557Stjr 504131557Stjrstatic int filename_mask; /* If zero, output nulls after filenames. */ 50553451Speterstatic int out_quiet; /* Suppress all normal output. */ 50653451Speterstatic int out_invert; /* Print nonmatching stuff. */ 50753451Speterstatic int out_file; /* Print filenames. */ 50853451Speterstatic int out_line; /* Print line numbers. */ 50953451Speterstatic int out_byte; /* Print byte offsets. */ 51053451Speterstatic int out_before; /* Lines of leading context. */ 51153451Speterstatic int out_after; /* Lines of trailing context. */ 51253477Sobrienstatic int count_matches; /* Count matching lines. */ 51353477Sobrienstatic int list_files; /* List matching files. */ 51453477Sobrienstatic int no_filenames; /* Suppress file names. */ 515131557Stjrstatic off_t max_count; /* Stop after outputting this many 516131557Stjr lines from an input file. */ 517131557Stjrstatic int line_buffered; /* If nonzero, use line buffering, i.e. 518131557Stjr fflush everyline out. */ 519131557Stjrstatic char *label = NULL; /* Fake filename for stdin */ 52053451Speter 521131557Stjr 52253451Speter/* Internal variables to keep track of byte count, context, etc. */ 523131557Stjrstatic uintmax_t totalcc; /* Total character count before bufbeg. */ 524131557Stjrstatic char const *lastnl; /* Pointer after last newline counted. */ 525131557Stjrstatic char const *lastout; /* Pointer after last character output; 52653451Speter NULL if no character has been output 52753451Speter or if it's conceptually before bufbeg. */ 528131557Stjrstatic uintmax_t totalnl; /* Total newline count before lastnl. */ 529131557Stjrstatic off_t outleft; /* Maximum number of lines to be output. */ 530131557Stjrstatic int pending; /* Pending lines of output. 531131557Stjr Always kept 0 if out_quiet is true. */ 532131557Stjrstatic int done_on_match; /* Stop scanning file on first match. */ 533131557Stjrstatic int exit_on_match; /* Exit on first match. */ 53453451Speter 535131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 53653477Sobrien# include "dosbuf.c" 53753477Sobrien#endif 53853477Sobrien 539131557Stjr/* Add two numbers that count input bytes or lines, and report an 540131557Stjr error if the addition overflows. */ 541131557Stjrstatic uintmax_t 542131557Stjradd_count (uintmax_t a, uintmax_t b) 543131557Stjr{ 544131557Stjr uintmax_t sum = a + b; 545131557Stjr if (sum < a) 546131557Stjr error (2, 0, _("input is too large to count")); 547131557Stjr return sum; 548131557Stjr} 549131557Stjr 55053451Speterstatic void 551131557Stjrnlscan (char const *lim) 55253451Speter{ 553131557Stjr size_t newlines = 0; 554131557Stjr char const *beg; 555131557Stjr for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++) 556131557Stjr newlines++; 557131557Stjr totalnl = add_count (totalnl, newlines); 55855379Sobrien lastnl = lim; 55953451Speter} 56053451Speter 561131557Stjr/* Print a byte offset, followed by a character separator. */ 56253451Speterstatic void 563131557Stjrprint_offset_sep (uintmax_t pos, char sep) 56453477Sobrien{ 565131557Stjr /* Do not rely on printf to print pos, since uintmax_t may be longer 566131557Stjr than long, and long long is not portable. */ 56753477Sobrien 56853477Sobrien char buf[sizeof pos * CHAR_BIT]; 56953477Sobrien char *p = buf + sizeof buf - 1; 57053477Sobrien *p = sep; 57153477Sobrien 57253477Sobrien do 57353477Sobrien *--p = '0' + pos % 10; 57453477Sobrien while ((pos /= 10) != 0); 57553477Sobrien 57653477Sobrien fwrite (p, 1, buf + sizeof buf - p, stdout); 57753477Sobrien} 57853477Sobrien 57953477Sobrienstatic void 580131557Stjrprline (char const *beg, char const *lim, int sep) 58153451Speter{ 58253451Speter if (out_file) 58355379Sobrien printf ("%s%c", filename, sep & filename_mask); 58453451Speter if (out_line) 58553451Speter { 58653477Sobrien nlscan (beg); 587131557Stjr totalnl = add_count (totalnl, 1); 588131557Stjr print_offset_sep (totalnl, sep); 58953451Speter lastnl = lim; 59053451Speter } 59153451Speter if (out_byte) 59253477Sobrien { 593131557Stjr uintmax_t pos = add_count (totalcc, beg - bufbeg); 594131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 59553477Sobrien pos = dossified_pos (pos); 59653477Sobrien#endif 59753477Sobrien print_offset_sep (pos, sep); 59853477Sobrien } 599131557Stjr if (only_matching) 600131557Stjr { 601131557Stjr size_t match_size; 602131557Stjr size_t match_offset; 603131557Stjr while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1)) 604131557Stjr != (size_t) -1) 605131557Stjr { 606131557Stjr char const *b = beg + match_offset; 607131557Stjr if (b == lim) 608131557Stjr break; 609131557Stjr if (match_size == 0) 610131557Stjr break; 611131557Stjr if(color_option) 612131557Stjr printf("\33[%sm", grep_color); 613131557Stjr fwrite(b, sizeof (char), match_size, stdout); 614131557Stjr if(color_option) 615131557Stjr fputs("\33[00m", stdout); 616131557Stjr fputs("\n", stdout); 617131557Stjr beg = b + match_size; 618131557Stjr } 619131557Stjr lastout = lim; 620131557Stjr if(line_buffered) 621131557Stjr fflush(stdout); 622131557Stjr return; 623131557Stjr } 624131557Stjr if (color_option) 625131557Stjr { 626131557Stjr size_t match_size; 627131557Stjr size_t match_offset; 628131557Stjr if(match_icase) 629131557Stjr { 630131557Stjr /* Yuck, this is tricky */ 631131557Stjr char *buf = (char*) xmalloc (lim - beg); 632131557Stjr char *ibeg = buf; 633131557Stjr char *ilim = ibeg + (lim - beg); 634131557Stjr int i; 635131557Stjr for (i = 0; i < lim - beg; i++) 636131557Stjr ibeg[i] = tolower (beg[i]); 637131557Stjr while ((match_offset = (*execute) (ibeg, ilim-ibeg, &match_size, 1)) 638131557Stjr != (size_t) -1) 639131557Stjr { 640131557Stjr char const *b = beg + match_offset; 641131557Stjr if (b == lim) 642131557Stjr break; 643131557Stjr fwrite (beg, sizeof (char), match_offset, stdout); 644131557Stjr printf ("\33[%sm", grep_color); 645131557Stjr fwrite (b, sizeof (char), match_size, stdout); 646131557Stjr fputs ("\33[00m", stdout); 647131557Stjr beg = b + match_size; 648131557Stjr ibeg = ibeg + match_offset + match_size; 649131557Stjr } 650131557Stjr fwrite (beg, 1, lim - beg, stdout); 651131557Stjr free (buf); 652131557Stjr lastout = lim; 653131557Stjr return; 654131557Stjr } 655131557Stjr while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1)) 656131557Stjr != (size_t) -1) 657131557Stjr { 658131557Stjr char const *b = beg + match_offset; 659131557Stjr /* Avoid matching the empty line at the end of the buffer. */ 660131557Stjr if (b == lim) 661131557Stjr break; 662131557Stjr /* Avoid hanging on grep --color "" foo */ 663131557Stjr if (match_size == 0) 664131557Stjr break; 665131557Stjr fwrite (beg, sizeof (char), match_offset, stdout); 666131557Stjr printf ("\33[%sm", grep_color); 667131557Stjr fwrite (b, sizeof (char), match_size, stdout); 668131557Stjr fputs ("\33[00m", stdout); 669131557Stjr beg = b + match_size; 670131557Stjr } 671131557Stjr } 67253477Sobrien fwrite (beg, 1, lim - beg, stdout); 67353477Sobrien if (ferror (stdout)) 674131557Stjr error (0, errno, _("writing output")); 67553451Speter lastout = lim; 676131557Stjr if (line_buffered) 677131557Stjr fflush (stdout); 67853451Speter} 67953451Speter 680131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends 681131557Stjr at the next matching line when OUTLEFT is 0. */ 68253451Speterstatic void 683131557Stjrprpending (char const *lim) 68453451Speter{ 68553451Speter if (!lastout) 68653451Speter lastout = bufbeg; 68753451Speter while (pending > 0 && lastout < lim) 68853451Speter { 689131557Stjr char const *nl = memchr (lastout, eolbyte, lim - lastout); 690131557Stjr size_t match_size; 69153451Speter --pending; 692131557Stjr if (outleft 693131557Stjr || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1) 694131557Stjr == !out_invert)) 695131557Stjr prline (lastout, nl + 1, '-'); 69653451Speter else 697131557Stjr pending = 0; 69853451Speter } 69953451Speter} 70053451Speter 70153451Speter/* Print the lines between BEG and LIM. Deal with context crap. 702131557Stjr If NLINESP is non-null, store a count of lines between BEG and LIM. */ 70353451Speterstatic void 704131557Stjrprtext (char const *beg, char const *lim, int *nlinesp) 70553451Speter{ 70653451Speter static int used; /* avoid printing "--" before any output */ 707131557Stjr char const *bp, *p; 70855379Sobrien char eol = eolbyte; 70953451Speter int i, n; 71053451Speter 71153451Speter if (!out_quiet && pending > 0) 71253477Sobrien prpending (beg); 71353451Speter 71453451Speter p = beg; 71553451Speter 71653451Speter if (!out_quiet) 71753451Speter { 71853451Speter /* Deal with leading context crap. */ 71953451Speter 72053451Speter bp = lastout ? lastout : bufbeg; 72153451Speter for (i = 0; i < out_before; ++i) 72253451Speter if (p > bp) 72353451Speter do 72453451Speter --p; 725131557Stjr while (p[-1] != eol); 72653451Speter 72753451Speter /* We only print the "--" separator if our output is 72853451Speter discontiguous from the last output in the file. */ 72953451Speter if ((out_before || out_after) && used && p != lastout) 73053477Sobrien puts ("--"); 73153451Speter 73253451Speter while (p < beg) 73353451Speter { 734131557Stjr char const *nl = memchr (p, eol, beg - p); 735131557Stjr nl++; 736131557Stjr prline (p, nl, '-'); 737131557Stjr p = nl; 73853451Speter } 73953451Speter } 74053451Speter 74153451Speter if (nlinesp) 74253451Speter { 74353451Speter /* Caller wants a line count. */ 744131557Stjr for (n = 0; p < lim && n < outleft; n++) 74553451Speter { 746131557Stjr char const *nl = memchr (p, eol, lim - p); 747131557Stjr nl++; 74853451Speter if (!out_quiet) 74953477Sobrien prline (p, nl, ':'); 75053451Speter p = nl; 75153451Speter } 75253451Speter *nlinesp = n; 753131557Stjr 754131557Stjr /* relying on it that this function is never called when outleft = 0. */ 755131557Stjr after_last_match = bufoffset - (buflim - p); 75653451Speter } 75753451Speter else 75853451Speter if (!out_quiet) 75953477Sobrien prline (beg, lim, ':'); 76053451Speter 76155379Sobrien pending = out_quiet ? 0 : out_after; 76253451Speter used = 1; 76353451Speter} 76453451Speter 76553451Speter/* Scan the specified portion of the buffer, matching lines (or 76653451Speter between matching lines if OUT_INVERT is true). Return a count of 76753451Speter lines printed. */ 76853451Speterstatic int 769131557Stjrgrepbuf (char const *beg, char const *lim) 77053451Speter{ 77153451Speter int nlines, n; 772131557Stjr register char const *p; 773131557Stjr size_t match_offset; 774131557Stjr size_t match_size; 77553451Speter 77653451Speter nlines = 0; 77753451Speter p = beg; 778131557Stjr while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1) 77953451Speter { 780131557Stjr char const *b = p + match_offset; 781131557Stjr char const *endp = b + match_size; 78253451Speter /* Avoid matching the empty line at the end of the buffer. */ 783131557Stjr if (b == lim) 78453451Speter break; 78553451Speter if (!out_invert) 78653451Speter { 78753477Sobrien prtext (b, endp, (int *) 0); 788131557Stjr nlines++; 789131557Stjr outleft--; 790131557Stjr if (!outleft || done_on_match) 791131557Stjr { 792131557Stjr if (exit_on_match) 793131557Stjr exit (0); 794131557Stjr after_last_match = bufoffset - (buflim - endp); 795131557Stjr return nlines; 796131557Stjr } 79753451Speter } 79853451Speter else if (p < b) 79953451Speter { 80053477Sobrien prtext (p, b, &n); 80153451Speter nlines += n; 802131557Stjr outleft -= n; 803131557Stjr if (!outleft) 804131557Stjr return nlines; 80553451Speter } 80653451Speter p = endp; 80753451Speter } 80853451Speter if (out_invert && p < lim) 80953451Speter { 81053477Sobrien prtext (p, lim, &n); 81153451Speter nlines += n; 812131557Stjr outleft -= n; 81353451Speter } 81453451Speter return nlines; 81553451Speter} 81653451Speter 81753477Sobrien/* Search a given file. Normally, return a count of lines printed; 81853477Sobrien but if the file is a directory and we search it recursively, then 81953477Sobrien return -2 if there was a match, and -1 otherwise. */ 82053451Speterstatic int 82156920Srugrep (int fd, char const *file, struct stats *stats) 82253451Speter{ 82353451Speter int nlines, i; 82453477Sobrien int not_text; 82553451Speter size_t residue, save; 826131557Stjr char oldc; 827131557Stjr char *beg; 828131557Stjr char *lim; 82955379Sobrien char eol = eolbyte; 83053451Speter 83153477Sobrien if (!reset (fd, file, stats)) 83253477Sobrien return 0; 83353451Speter 83453477Sobrien if (file && directories == RECURSE_DIRECTORIES 83553477Sobrien && S_ISDIR (stats->stat.st_mode)) 83653477Sobrien { 83753477Sobrien /* Close fd now, so that we don't open a lot of file descriptors 83853477Sobrien when we recurse deeply. */ 839104555Sobrien if (BZflag && bzbufdesc) 840103372Sobrien BZ2_bzclose(bzbufdesc); 841103372Sobrien else 84253477Sobrien#if HAVE_LIBZ > 0 84353477Sobrien if (Zflag) 84453477Sobrien gzclose(gzbufdesc); 84553477Sobrien else 84653477Sobrien#endif 84753477Sobrien if (close (fd) != 0) 848131557Stjr error (0, errno, "%s", file); 84953477Sobrien return grepdir (file, stats) - 2; 85053477Sobrien } 85153477Sobrien 85253451Speter totalcc = 0; 85353451Speter lastout = 0; 85453451Speter totalnl = 0; 855131557Stjr outleft = max_count; 856131557Stjr after_last_match = 0; 85753451Speter pending = 0; 85853451Speter 85953451Speter nlines = 0; 86053451Speter residue = 0; 86153451Speter save = 0; 86253451Speter 86355379Sobrien if (! fillbuf (save, stats)) 86453451Speter { 865131557Stjr if (! is_EISDIR (errno, file)) 866131557Stjr suppressible_error (filename, errno); 86756233Sru return 0; 86853477Sobrien } 86953451Speter 87056233Sru not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet) 87156233Sru || binary_files == WITHOUT_MATCH_BINARY_FILES) 87255379Sobrien && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg)); 87356233Sru if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES) 87456233Sru return 0; 87553477Sobrien done_on_match += not_text; 87653477Sobrien out_quiet += not_text; 87753451Speter 87853477Sobrien for (;;) 87953477Sobrien { 88053451Speter lastnl = bufbeg; 88153451Speter if (lastout) 88253451Speter lastout = bufbeg; 883131557Stjr 884131557Stjr beg = bufbeg + save; 885131557Stjr 886131557Stjr /* no more data to scan (eof) except for maybe a residue -> break */ 887131557Stjr if (beg == buflim) 88853451Speter break; 889131557Stjr 890131557Stjr /* Determine new residue (the length of an incomplete line at the end of 891131557Stjr the buffer, 0 means there is no incomplete last line). */ 892131557Stjr oldc = beg[-1]; 893131557Stjr beg[-1] = eol; 894131557Stjr for (lim = buflim; lim[-1] != eol; lim--) 895131557Stjr continue; 896131557Stjr beg[-1] = oldc; 897131557Stjr if (lim == beg) 898131557Stjr lim = beg - residue; 899131557Stjr beg -= residue; 90053451Speter residue = buflim - lim; 901131557Stjr 90253451Speter if (beg < lim) 90353451Speter { 904131557Stjr if (outleft) 905131557Stjr nlines += grepbuf (beg, lim); 90653451Speter if (pending) 90753477Sobrien prpending (lim); 908131557Stjr if((!outleft && !pending) || (nlines && done_on_match && !out_invert)) 90953477Sobrien goto finish_grep; 91053451Speter } 911131557Stjr 912131557Stjr /* The last OUT_BEFORE lines at the end of the buffer will be needed as 913131557Stjr leading context if there is a matching line at the begin of the 914131557Stjr next data. Make beg point to their begin. */ 91553451Speter i = 0; 91653451Speter beg = lim; 91753451Speter while (i < out_before && beg > bufbeg && beg != lastout) 91853451Speter { 91953451Speter ++i; 92053451Speter do 92153451Speter --beg; 922131557Stjr while (beg[-1] != eol); 92353451Speter } 924131557Stjr 925131557Stjr /* detect if leading context is discontinuous from last printed line. */ 92653451Speter if (beg != lastout) 92753451Speter lastout = 0; 928131557Stjr 929131557Stjr /* Handle some details and read more data to scan. */ 93053451Speter save = residue + lim - beg; 931131557Stjr if (out_byte) 932131557Stjr totalcc = add_count (totalcc, buflim - bufbeg - save); 93353451Speter if (out_line) 93453477Sobrien nlscan (beg); 93555379Sobrien if (! fillbuf (save, stats)) 93653477Sobrien { 937131557Stjr if (! is_EISDIR (errno, file)) 938131557Stjr suppressible_error (filename, errno); 93953477Sobrien goto finish_grep; 94053477Sobrien } 94153451Speter } 94253451Speter if (residue) 94353451Speter { 94456920Sru *buflim++ = eol; 945131557Stjr if (outleft) 946131557Stjr nlines += grepbuf (bufbeg + save - residue, buflim); 94753451Speter if (pending) 948131557Stjr prpending (buflim); 94953451Speter } 95053477Sobrien 95153477Sobrien finish_grep: 95253477Sobrien done_on_match -= not_text; 95353477Sobrien out_quiet -= not_text; 95453477Sobrien if ((not_text & ~out_quiet) && nlines != 0) 95553477Sobrien printf (_("Binary file %s matches\n"), filename); 95653451Speter return nlines; 95753451Speter} 95853451Speter 95953477Sobrienstatic int 96056920Srugrepfile (char const *file, struct stats *stats) 96153477Sobrien{ 96253477Sobrien int desc; 96353477Sobrien int count; 96453477Sobrien int status; 96553477Sobrien 96653477Sobrien if (! file) 96753477Sobrien { 96853477Sobrien desc = 0; 969131557Stjr filename = label ? label : _("(standard input)"); 97053477Sobrien } 97153477Sobrien else 97253477Sobrien { 97355379Sobrien while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR) 97455379Sobrien continue; 97553477Sobrien 97653477Sobrien if (desc < 0) 97753477Sobrien { 97853477Sobrien int e = errno; 979131557Stjr 98053477Sobrien if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES) 98153477Sobrien { 98253477Sobrien if (stat (file, &stats->stat) != 0) 98353477Sobrien { 984131557Stjr error (0, errno, "%s", file); 98553477Sobrien return 1; 98653477Sobrien } 98753477Sobrien 98853477Sobrien return grepdir (file, stats); 98953477Sobrien } 990131557Stjr 99153477Sobrien if (!suppress_errors) 99253477Sobrien { 99353477Sobrien if (directories == SKIP_DIRECTORIES) 99453477Sobrien switch (e) 99553477Sobrien { 996131557Stjr#if defined(EISDIR) 99753477Sobrien case EISDIR: 99853477Sobrien return 1; 99953451Speter#endif 100053477Sobrien case EACCES: 100153477Sobrien /* When skipping directories, don't worry about 100253477Sobrien directories that can't be opened. */ 1003131557Stjr if (isdir (file)) 100453477Sobrien return 1; 100553477Sobrien break; 100653477Sobrien } 100753477Sobrien } 100853477Sobrien 1009131557Stjr suppressible_error (file, e); 101053477Sobrien return 1; 101153477Sobrien } 101253477Sobrien 101353477Sobrien filename = file; 101453477Sobrien } 101553477Sobrien 1016131557Stjr#if defined(SET_BINARY) 101753477Sobrien /* Set input to binary mode. Pipes are simulated with files 101853477Sobrien on DOS, so this includes the case of "foo | grep bar". */ 101953477Sobrien if (!isatty (desc)) 102053477Sobrien SET_BINARY (desc); 102153477Sobrien#endif 102253477Sobrien 102353477Sobrien count = grep (desc, file, stats); 102453477Sobrien if (count < 0) 102553477Sobrien status = count + 2; 102653477Sobrien else 102753477Sobrien { 102853477Sobrien if (count_matches) 102953477Sobrien { 103053477Sobrien if (out_file) 103155379Sobrien printf ("%s%c", filename, ':' & filename_mask); 103253477Sobrien printf ("%d\n", count); 103353477Sobrien } 103453477Sobrien 103555379Sobrien status = !count; 103655379Sobrien if (list_files == 1 - 2 * status) 103755379Sobrien printf ("%s%c", filename, '\n' & filename_mask); 103853477Sobrien 1039104555Sobrien if (BZflag && bzbufdesc) 1040103372Sobrien BZ2_bzclose(bzbufdesc); 1041103372Sobrien else 104253451Speter#if HAVE_LIBZ > 0 104353477Sobrien if (Zflag) 104453477Sobrien gzclose(gzbufdesc); 104553477Sobrien else 104653451Speter#endif 1047131557Stjr if (! file) 1048131557Stjr { 1049131557Stjr off_t required_offset = outleft ? bufoffset : after_last_match; 1050131557Stjr if ((bufmapped || required_offset != bufoffset) 1051131557Stjr && lseek (desc, required_offset, SEEK_SET) < 0 1052131557Stjr && S_ISREG (stats->stat.st_mode)) 1053131557Stjr error (0, errno, "%s", filename); 1054131557Stjr } 1055131557Stjr else 105655379Sobrien while (close (desc) != 0) 105755379Sobrien if (errno != EINTR) 105855379Sobrien { 1059131557Stjr error (0, errno, "%s", file); 106055379Sobrien break; 106155379Sobrien } 106253477Sobrien } 106353451Speter 106453477Sobrien return status; 106553477Sobrien} 106653477Sobrien 106753477Sobrienstatic int 1068131557Stjrgrepdir (char const *dir, struct stats const *stats) 106953477Sobrien{ 107053477Sobrien int status = 1; 1071131557Stjr struct stats const *ancestor; 107253477Sobrien char *name_space; 107353477Sobrien 1074131557Stjr /* Mingw32 does not support st_ino. No known working hosts use zero 1075131557Stjr for st_ino, so assume that the Mingw32 bug applies if it's zero. */ 1076131557Stjr if (stats->stat.st_ino) 1077131557Stjr for (ancestor = stats; (ancestor = ancestor->parent) != 0; ) 1078131557Stjr if (ancestor->stat.st_ino == stats->stat.st_ino 1079131557Stjr && ancestor->stat.st_dev == stats->stat.st_dev) 1080131557Stjr { 1081131557Stjr if (!suppress_errors) 1082131557Stjr error (0, 0, _("warning: %s: %s\n"), dir, 108353477Sobrien _("recursive directory loop")); 1084131557Stjr return 1; 1085131557Stjr } 108653477Sobrien 1087131557Stjr name_space = savedir (dir, stats->stat.st_size, included_patterns, 1088131557Stjr excluded_patterns); 108953477Sobrien 109053477Sobrien if (! name_space) 109153477Sobrien { 109253477Sobrien if (errno) 1093131557Stjr suppressible_error (dir, errno); 109453477Sobrien else 1095131557Stjr xalloc_die (); 109653477Sobrien } 109753477Sobrien else 109853477Sobrien { 109953477Sobrien size_t dirlen = strlen (dir); 110053477Sobrien int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir) 110153477Sobrien || IS_SLASH (dir[dirlen - 1])); 110253477Sobrien char *file = NULL; 1103131557Stjr char const *namep = name_space; 110453477Sobrien struct stats child; 110553477Sobrien child.parent = stats; 110653477Sobrien out_file += !no_filenames; 110753477Sobrien while (*namep) 110853477Sobrien { 110953477Sobrien size_t namelen = strlen (namep); 111053477Sobrien file = xrealloc (file, dirlen + 1 + namelen + 1); 111153477Sobrien strcpy (file, dir); 111253477Sobrien file[dirlen] = '/'; 111353477Sobrien strcpy (file + dirlen + needs_slash, namep); 111453477Sobrien namep += namelen + 1; 111553477Sobrien status &= grepfile (file, &child); 111653477Sobrien } 111753477Sobrien out_file -= !no_filenames; 111853477Sobrien if (file) 111953477Sobrien free (file); 112053477Sobrien free (name_space); 112153477Sobrien } 112253477Sobrien 112353477Sobrien return status; 112453477Sobrien} 112553477Sobrien 112653451Speterstatic void 112756920Sruusage (int status) 112853451Speter{ 112953477Sobrien if (status != 0) 113053477Sobrien { 1131131557Stjr fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"), 1132131557Stjr program_name); 1133131557Stjr fprintf (stderr, _("Try `%s --help' for more information.\n"), 1134131557Stjr program_name); 113553477Sobrien } 113653477Sobrien else 113753477Sobrien { 1138131557Stjr printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name); 113953477Sobrien printf (_("\ 114053477SobrienSearch for PATTERN in each FILE or standard input.\n\ 114156920SruExample: %s -i 'hello world' menu.h main.c\n\ 114253477Sobrien\n\ 1143131557StjrRegexp selection and interpretation:\n"), program_name); 114455379Sobrien printf (_("\ 114553477Sobrien -E, --extended-regexp PATTERN is an extended regular expression\n\ 114655379Sobrien -F, --fixed-strings PATTERN is a set of newline-separated strings\n\ 1147131557Stjr -G, --basic-regexp PATTERN is a basic regular expression\n\ 1148131557Stjr -P, --perl-regexp PATTERN is a Perl regular expression\n")); 114955379Sobrien printf (_("\ 115053477Sobrien -e, --regexp=PATTERN use PATTERN as a regular expression\n\ 115153477Sobrien -f, --file=FILE obtain PATTERN from FILE\n\ 115253477Sobrien -i, --ignore-case ignore case distinctions\n\ 115353477Sobrien -w, --word-regexp force PATTERN to match only whole words\n\ 115455379Sobrien -x, --line-regexp force PATTERN to match only whole lines\n\ 115555379Sobrien -z, --null-data a data line ends in 0 byte, not newline\n")); 115653477Sobrien printf (_("\ 115753477Sobrien\n\ 115853477SobrienMiscellaneous:\n\ 115953477Sobrien -s, --no-messages suppress error messages\n\ 116055379Sobrien -v, --invert-match select non-matching lines\n\ 116153477Sobrien -V, --version print version information and exit\n\ 116255379Sobrien --help display this help and exit\n\ 1163103372Sobrien -J, --bz2decompress decompress bzip2'ed input before searching\n\ 116453477Sobrien -Z, --decompress decompress input before searching (HAVE_LIBZ=1)\n\ 116555379Sobrien --mmap use memory-mapped input if possible\n")); 116653477Sobrien printf (_("\ 116753477Sobrien\n\ 116853477SobrienOutput control:\n\ 1169131557Stjr -m, --max-count=NUM stop after NUM matches\n\ 117053477Sobrien -b, --byte-offset print the byte offset with output lines\n\ 117153477Sobrien -n, --line-number print line number with output lines\n\ 1172131557Stjr --line-buffered flush output on every line\n\ 117353477Sobrien -H, --with-filename print the filename for each match\n\ 117453477Sobrien -h, --no-filename suppress the prefixing filename on output\n\ 1175131557Stjr --label=LABEL print LABEL as filename for standard input\n\ 1176131557Stjr -o, --only-matching show only the part of a line matching PATTERN\n\ 117753477Sobrien -q, --quiet, --silent suppress all normal output\n\ 117856233Sru --binary-files=TYPE assume that binary files are TYPE\n\ 1179131557Stjr TYPE is 'binary', 'text', or 'without-match'\n\ 118056920Sru -a, --text equivalent to --binary-files=text\n\ 118156920Sru -I equivalent to --binary-files=without-match\n\ 118253477Sobrien -d, --directories=ACTION how to handle directories\n\ 1183131557Stjr ACTION is 'read', 'recurse', or 'skip'\n\ 1184131557Stjr -D, --devices=ACTION how to handle devices, FIFOs and sockets\n\ 1185131557Stjr ACTION is 'read' or 'skip'\n\ 1186131557Stjr -R, -r, --recursive equivalent to --directories=recurse\n\ 1187131557Stjr --include=PATTERN files that match PATTERN will be examined\n\ 1188131557Stjr --exclude=PATTERN files that match PATTERN will be skipped.\n\ 1189131557Stjr --exclude-from=FILE files that match PATTERN in FILE will be skipped.\n\ 119053477Sobrien -L, --files-without-match only print FILE names containing no match\n\ 119153477Sobrien -l, --files-with-matches only print FILE names containing matches\n\ 119255379Sobrien -c, --count only print a count of matching lines per FILE\n\ 119355379Sobrien --null print 0 byte after FILE name\n")); 119453477Sobrien printf (_("\ 119553477Sobrien\n\ 119653477SobrienContext control:\n\ 119753477Sobrien -B, --before-context=NUM print NUM lines of leading context\n\ 119853477Sobrien -A, --after-context=NUM print NUM lines of trailing context\n\ 1199131557Stjr -C, --context=NUM print NUM lines of output context\n\ 120053477Sobrien -NUM same as --context=NUM\n\ 1201131557Stjr --color[=WHEN],\n\ 1202131557Stjr --colour[=WHEN] use markers to distinguish the matching string\n\ 1203131557Stjr WHEN may be `always', `never' or `auto'.\n\ 120453477Sobrien -U, --binary do not strip CR characters at EOL (MSDOS)\n\ 120553477Sobrien -u, --unix-byte-offsets report offsets as if CRs were not there (MSDOS)\n\ 120653477Sobrien\n\ 120755379Sobrien`egrep' means `grep -E'. `fgrep' means `grep -F'.\n\ 120855379SobrienWith no FILE, or when FILE is -, read standard input. If less than\n\ 120955379Sobrientwo FILEs given, assume -h. Exit status is 0 if match, 1 if no match,\n\ 121055379Sobrienand 2 if trouble.\n")); 121153477Sobrien printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n")); 121253477Sobrien } 121353477Sobrien exit (status); 121453451Speter} 121553451Speter 121655379Sobrien/* Set the matcher to M, reporting any conflicts. */ 121755379Sobrienstatic void 121856920Srusetmatcher (char const *m) 121955379Sobrien{ 122055379Sobrien if (matcher && strcmp (matcher, m) != 0) 1221131557Stjr error (2, 0, _("conflicting matchers specified")); 122255379Sobrien matcher = m; 122355379Sobrien} 122455379Sobrien 122553451Speter/* Go through the matchers vector and look for the specified matcher. 122653451Speter If we find it, install it in compile and execute, and return 1. */ 122753477Sobrienstatic int 122856920Sruinstall_matcher (char const *name) 122953451Speter{ 123053451Speter int i; 1231131557Stjr#if defined(HAVE_SETRLIMIT) 123253477Sobrien struct rlimit rlim; 123353477Sobrien#endif 123453451Speter 1235131557Stjr for (i = 0; matchers[i].compile; i++) 123653477Sobrien if (strcmp (name, matchers[i].name) == 0) 123753451Speter { 123853451Speter compile = matchers[i].compile; 123953451Speter execute = matchers[i].execute; 1240131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK) 124153477Sobrien /* I think every platform needs to do this, so that regex.c 124253477Sobrien doesn't oveflow the stack. The default value of 124353477Sobrien `re_max_failures' is too large for some platforms: it needs 124453477Sobrien more than 3MB-large stack. 124553477Sobrien 124653477Sobrien The test for HAVE_SETRLIMIT should go into `configure'. */ 124753477Sobrien if (!getrlimit (RLIMIT_STACK, &rlim)) 124853477Sobrien { 124953477Sobrien long newlim; 125053477Sobrien extern long int re_max_failures; /* from regex.c */ 125153477Sobrien 125253477Sobrien /* Approximate the amount regex.c needs, plus some more. */ 125353477Sobrien newlim = re_max_failures * 2 * 20 * sizeof (char *); 125453477Sobrien if (newlim > rlim.rlim_max) 125553477Sobrien { 125653477Sobrien newlim = rlim.rlim_max; 125753477Sobrien re_max_failures = newlim / (2 * 20 * sizeof (char *)); 125853477Sobrien } 125953477Sobrien if (rlim.rlim_cur < newlim) 1260131557Stjr { 1261131557Stjr rlim.rlim_cur = newlim; 1262131557Stjr setrlimit (RLIMIT_STACK, &rlim); 1263131557Stjr } 126453477Sobrien } 126553477Sobrien#endif 126653451Speter return 1; 126753451Speter } 126853451Speter return 0; 126953451Speter} 127053451Speter 127153705Sobrien/* Find the white-space-separated options specified by OPTIONS, and 127253705Sobrien using BUF to store copies of these options, set ARGV[0], ARGV[1], 127353705Sobrien etc. to the option copies. Return the number N of options found. 127453705Sobrien Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0] 127553705Sobrien etc. Backslash can be used to escape whitespace (and backslashes). */ 127653705Sobrienstatic int 127756920Sruprepend_args (char const *options, char *buf, char **argv) 127853705Sobrien{ 127953705Sobrien char const *o = options; 128053705Sobrien char *b = buf; 128153705Sobrien int n = 0; 128253705Sobrien 128353705Sobrien for (;;) 128453705Sobrien { 128553705Sobrien while (ISSPACE ((unsigned char) *o)) 128653705Sobrien o++; 128753705Sobrien if (!*o) 128853705Sobrien return n; 128953705Sobrien if (argv) 129053705Sobrien argv[n] = b; 129153705Sobrien n++; 129253705Sobrien 129353705Sobrien do 129453705Sobrien if ((*b++ = *o++) == '\\' && *o) 129553705Sobrien b[-1] = *o++; 129653705Sobrien while (*o && ! ISSPACE ((unsigned char) *o)); 129753705Sobrien 129853705Sobrien *b++ = '\0'; 129953705Sobrien } 130053705Sobrien} 130153705Sobrien 130253705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument 130353705Sobrien vector of a main program with argument count *PARGC and argument 130453705Sobrien vector *PARGV. */ 130553705Sobrienstatic void 130656920Sruprepend_default_options (char const *options, int *pargc, char ***pargv) 130753705Sobrien{ 130853705Sobrien if (options) 130953705Sobrien { 131053705Sobrien char *buf = xmalloc (strlen (options) + 1); 131153705Sobrien int prepended = prepend_args (options, buf, (char **) NULL); 131253705Sobrien int argc = *pargc; 131353705Sobrien char * const *argv = *pargv; 131453705Sobrien char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); 131553705Sobrien *pargc = prepended + argc; 131653705Sobrien *pargv = pp; 131753705Sobrien *pp++ = *argv++; 131853705Sobrien pp += prepend_args (options, buf, pp); 131953705Sobrien while ((*pp++ = *argv++)) 132053705Sobrien continue; 132153705Sobrien } 132253705Sobrien} 132353705Sobrien 1324131557Stjr/* Get the next non-digit option from ARGC and ARGV. 1325131557Stjr Return -1 if there are no more options. 1326131557Stjr Process any digit options that were encountered on the way, 1327131557Stjr and store the resulting integer into *DEFAULT_CONTEXT. */ 1328131557Stjrstatic int 1329131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context) 1330131557Stjr{ 1331131557Stjr int opt; 1332131557Stjr char buf[sizeof (uintmax_t) * CHAR_BIT + 4]; 1333131557Stjr char *p = buf; 1334131557Stjr 1335131557Stjr /* Set buf[0] to anything but '0', for the leading-zero test below. */ 1336131557Stjr buf[0] = '\0'; 1337131557Stjr 1338131557Stjr while (opt = getopt_long (argc, argv, short_options, long_options, NULL), 1339131557Stjr '0' <= opt && opt <= '9') 1340131557Stjr { 1341131557Stjr /* Suppress trivial leading zeros, to avoid incorrect 1342131557Stjr diagnostic on strings like 00000000000. */ 1343131557Stjr p -= buf[0] == '0'; 1344131557Stjr 1345131557Stjr *p++ = opt; 1346131557Stjr if (p == buf + sizeof buf - 4) 1347131557Stjr { 1348131557Stjr /* Too many digits. Append "..." to make context_length_arg 1349131557Stjr complain about "X...", where X contains the digits seen 1350131557Stjr so far. */ 1351131557Stjr strcpy (p, "..."); 1352131557Stjr p += 3; 1353131557Stjr break; 1354131557Stjr } 1355131557Stjr } 1356131557Stjr if (p != buf) 1357131557Stjr { 1358131557Stjr *p = '\0'; 1359131557Stjr context_length_arg (buf, default_context); 1360131557Stjr } 1361131557Stjr 1362131557Stjr return opt; 1363131557Stjr} 1364131557Stjr 136553451Speterint 136656920Srumain (int argc, char **argv) 136753451Speter{ 136853451Speter char *keys; 136953451Speter size_t keycc, oldcc, keyalloc; 137053477Sobrien int with_filenames; 137153477Sobrien int opt, cc, status; 137256920Sru int default_context; 137353451Speter FILE *fp; 137453451Speter extern char *optarg; 137553451Speter extern int optind; 137653477Sobrien 137753477Sobrien initialize_main (&argc, &argv); 1378131557Stjr program_name = argv[0]; 1379131557Stjr if (program_name && strrchr (program_name, '/')) 1380131557Stjr program_name = strrchr (program_name, '/') + 1; 138153477Sobrien 138253477Sobrien#if HAVE_LIBZ > 0 1383131557Stjr if (program_name[0] == 'z') { 138453477Sobrien Zflag = 1; 1385131557Stjr ++program_name; 138653477Sobrien } 138753451Speter#endif 1388131557Stjr if (program_name[0] == 'b') { 1389103372Sobrien BZflag = 1; 1390131557Stjr ++program_name; 1391103372Sobrien } 139253451Speter 139353477Sobrien#if defined(__MSDOS__) || defined(_WIN32) 139453477Sobrien /* DOS and MS-Windows use backslashes as directory separators, and usually 139553477Sobrien have an .exe suffix. They also have case-insensitive filesystems. */ 1396131557Stjr if (program_name) 139753477Sobrien { 1398131557Stjr char *p = program_name; 139953477Sobrien char *bslash = strrchr (argv[0], '\\'); 140053477Sobrien 1401131557Stjr if (bslash && bslash >= program_name) /* for mixed forward/backslash case */ 1402131557Stjr program_name = bslash + 1; 1403131557Stjr else if (program_name == argv[0] 140453477Sobrien && argv[0][0] && argv[0][1] == ':') /* "c:progname" */ 1405131557Stjr program_name = argv[0] + 2; 140653477Sobrien 140753477Sobrien /* Collapse the letter-case, so `strcmp' could be used hence. */ 140853477Sobrien for ( ; *p; p++) 140953477Sobrien if (*p >= 'A' && *p <= 'Z') 141053477Sobrien *p += 'a' - 'A'; 141153477Sobrien 141253477Sobrien /* Remove the .exe extension, if any. */ 1413131557Stjr if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0) 141453477Sobrien *p = '\0'; 141553477Sobrien } 141653451Speter#endif 141753451Speter 141853451Speter keys = NULL; 141953451Speter keycc = 0; 142053477Sobrien with_filenames = 0; 142155379Sobrien eolbyte = '\n'; 142255379Sobrien filename_mask = ~0; 142353477Sobrien 1424131557Stjr max_count = TYPE_MAXIMUM (off_t); 1425131557Stjr 142653477Sobrien /* The value -1 means to use DEFAULT_CONTEXT. */ 142753477Sobrien out_after = out_before = -1; 142853477Sobrien /* Default before/after context: chaged by -C/-NUM options */ 142953477Sobrien default_context = 0; 1430131557Stjr /* Changed by -o option */ 1431131557Stjr only_matching = 0; 143253477Sobrien 1433131557Stjr /* Internationalization. */ 1434131557Stjr#if defined(HAVE_SETLOCALE) 143553477Sobrien setlocale (LC_ALL, ""); 143653451Speter#endif 1437131557Stjr#if defined(ENABLE_NLS) 143853477Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 143953477Sobrien textdomain (PACKAGE); 144053451Speter#endif 144153451Speter 1442131557Stjr atexit (close_stdout); 1443131557Stjr 144453705Sobrien prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv); 144553705Sobrien 1446131557Stjr while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1) 144753451Speter switch (opt) 144853451Speter { 144953451Speter case 'A': 1450131557Stjr context_length_arg (optarg, &out_after); 145153451Speter break; 1452131557Stjr 145353451Speter case 'B': 1454131557Stjr context_length_arg (optarg, &out_before); 145553451Speter break; 1456131557Stjr 145753451Speter case 'C': 145853477Sobrien /* Set output match context, but let any explicit leading or 145953477Sobrien trailing amount specified with -A or -B stand. */ 1460131557Stjr context_length_arg (optarg, &default_context); 1461131557Stjr break; 1462131557Stjr 1463131557Stjr case 'D': 1464131557Stjr if (strcmp (optarg, "read") == 0) 1465131557Stjr devices = READ_DEVICES; 1466131557Stjr else if (strcmp (optarg, "skip") == 0) 1467131557Stjr devices = SKIP_DEVICES; 146853477Sobrien else 1469131557Stjr error (2, 0, _("unknown devices method")); 147053451Speter break; 1471131557Stjr 147253451Speter case 'E': 147355379Sobrien setmatcher ("egrep"); 147453451Speter break; 1475131557Stjr 147653451Speter case 'F': 147755379Sobrien setmatcher ("fgrep"); 147853451Speter break; 1479131557Stjr 1480131557Stjr case 'P': 1481131557Stjr setmatcher ("perl"); 1482131557Stjr break; 1483131557Stjr 148453451Speter case 'G': 148555379Sobrien setmatcher ("grep"); 148653451Speter break; 1487131557Stjr 148853477Sobrien case 'H': 148953477Sobrien with_filenames = 1; 149053477Sobrien break; 1491131557Stjr 149256920Sru case 'I': 149356920Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 149456920Sru break; 1495103372Sobrien case 'J': 1496104555Sobrien if (Zflag) 1497104555Sobrien { 1498104555Sobrien printf (_("Cannot mix -Z and -J.\n")); 1499104555Sobrien usage (2); 1500104555Sobrien } 1501103372Sobrien BZflag = 1; 1502103372Sobrien break; 1503131557Stjr 150455379Sobrien case 'U': 1505131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 150653477Sobrien dos_use_file_type = DOS_BINARY; 150755379Sobrien#endif 150853477Sobrien break; 1509131557Stjr 151053477Sobrien case 'u': 1511131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 151253477Sobrien dos_report_unix_offset = 1; 151355379Sobrien#endif 151453477Sobrien break; 1515131557Stjr 151653451Speter case 'V': 151753477Sobrien show_version = 1; 151853451Speter break; 1519131557Stjr 152053451Speter case 'X': 152155379Sobrien setmatcher (optarg); 152253451Speter break; 1523131557Stjr 152453451Speter case 'a': 152556233Sru binary_files = TEXT_BINARY_FILES; 152653451Speter break; 1527131557Stjr 152853451Speter case 'b': 152953451Speter out_byte = 1; 153053451Speter break; 1531131557Stjr 153253451Speter case 'c': 153353451Speter count_matches = 1; 153453451Speter break; 1535131557Stjr 153653477Sobrien case 'd': 153753477Sobrien if (strcmp (optarg, "read") == 0) 153853477Sobrien directories = READ_DIRECTORIES; 153953477Sobrien else if (strcmp (optarg, "skip") == 0) 154053477Sobrien directories = SKIP_DIRECTORIES; 154153477Sobrien else if (strcmp (optarg, "recurse") == 0) 154253477Sobrien directories = RECURSE_DIRECTORIES; 154353477Sobrien else 1544131557Stjr error (2, 0, _("unknown directories method")); 154553477Sobrien break; 1546131557Stjr 154753451Speter case 'e': 154853477Sobrien cc = strlen (optarg); 154953477Sobrien keys = xrealloc (keys, keycc + cc + 1); 155053477Sobrien strcpy (&keys[keycc], optarg); 155153451Speter keycc += cc; 155253477Sobrien keys[keycc++] = '\n'; 155353451Speter break; 1554131557Stjr 155553451Speter case 'f': 155653477Sobrien fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin; 155753451Speter if (!fp) 1558131557Stjr error (2, errno, "%s", optarg); 155953477Sobrien for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2) 156053451Speter ; 156153477Sobrien keys = xrealloc (keys, keyalloc); 156253451Speter oldcc = keycc; 156353477Sobrien while (!feof (fp) 156453477Sobrien && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0) 156553451Speter { 156653451Speter keycc += cc; 156753477Sobrien if (keycc == keyalloc - 1) 156853477Sobrien keys = xrealloc (keys, keyalloc *= 2); 156953451Speter } 157053451Speter if (fp != stdin) 157153451Speter fclose(fp); 157253477Sobrien /* Append final newline if file ended in non-newline. */ 157353477Sobrien if (oldcc != keycc && keys[keycc - 1] != '\n') 157453477Sobrien keys[keycc++] = '\n'; 157553451Speter break; 1576131557Stjr 157753451Speter case 'h': 157853451Speter no_filenames = 1; 157953451Speter break; 1580131557Stjr 158153451Speter case 'i': 158253451Speter case 'y': /* For old-timers . . . */ 158353451Speter match_icase = 1; 158453451Speter break; 1585131557Stjr 158653451Speter case 'L': 158753451Speter /* Like -l, except list files that don't contain matches. 158853451Speter Inspired by the same option in Hume's gre. */ 158953451Speter list_files = -1; 159053451Speter break; 1591131557Stjr 159253451Speter case 'l': 159353451Speter list_files = 1; 159453451Speter break; 1595131557Stjr 1596131557Stjr case 'm': 1597131557Stjr { 1598131557Stjr uintmax_t value; 1599131557Stjr switch (xstrtoumax (optarg, 0, 10, &value, "")) 1600131557Stjr { 1601131557Stjr case LONGINT_OK: 1602131557Stjr max_count = value; 1603131557Stjr if (0 <= max_count && max_count == value) 1604131557Stjr break; 1605131557Stjr /* Fall through. */ 1606131557Stjr case LONGINT_OVERFLOW: 1607131557Stjr max_count = TYPE_MAXIMUM (off_t); 1608131557Stjr break; 1609131557Stjr 1610131557Stjr default: 1611131557Stjr error (2, 0, _("invalid max count")); 1612131557Stjr } 1613131557Stjr } 1614131557Stjr break; 1615131557Stjr 161653451Speter case 'n': 161753451Speter out_line = 1; 161853451Speter break; 1619131557Stjr 1620131557Stjr case 'o': 1621131557Stjr only_matching = 1; 1622131557Stjr break; 1623131557Stjr 162453451Speter case 'q': 1625131557Stjr exit_on_match = 1; 1626131557Stjr close_stdout_set_status(0); 162753451Speter break; 1628131557Stjr 162953478Sobrien case 'R': 163053477Sobrien case 'r': 163153477Sobrien directories = RECURSE_DIRECTORIES; 163253477Sobrien break; 1633131557Stjr 163453451Speter case 's': 163553451Speter suppress_errors = 1; 163653451Speter break; 1637131557Stjr 163853451Speter case 'v': 163953451Speter out_invert = 1; 164053451Speter break; 1641131557Stjr 164253451Speter case 'w': 164353451Speter match_words = 1; 164453451Speter break; 1645131557Stjr 164653451Speter case 'x': 164753451Speter match_lines = 1; 164853451Speter break; 1649131557Stjr 165055379Sobrien case 'Z': 165155379Sobrien#if HAVE_LIBZ > 0 1652104555Sobrien if (BZflag) 1653104555Sobrien { 1654104555Sobrien printf (_("Cannot mix -J and -Z.\n")); 1655104555Sobrien usage (2); 1656104555Sobrien } 165755379Sobrien Zflag = 1; 165855379Sobrien#else 165955379Sobrien filename_mask = 0; 166055379Sobrien#endif 166155379Sobrien break; 1662131557Stjr 166355379Sobrien case 'z': 166455379Sobrien eolbyte = '\0'; 166555379Sobrien break; 1666131557Stjr 166756233Sru case BINARY_FILES_OPTION: 166856233Sru if (strcmp (optarg, "binary") == 0) 166956233Sru binary_files = BINARY_BINARY_FILES; 167056233Sru else if (strcmp (optarg, "text") == 0) 167156233Sru binary_files = TEXT_BINARY_FILES; 167256233Sru else if (strcmp (optarg, "without-match") == 0) 167356233Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 167456233Sru else 1675131557Stjr error (2, 0, _("unknown binary-files type")); 167656233Sru break; 1677131557Stjr 1678131557Stjr case COLOR_OPTION: 1679131557Stjr if(optarg) { 1680131557Stjr if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") || 1681131557Stjr !strcasecmp(optarg, "force")) 1682131557Stjr color_option = 1; 1683131557Stjr else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") || 1684131557Stjr !strcasecmp(optarg, "none")) 1685131557Stjr color_option = 0; 1686131557Stjr else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") || 1687131557Stjr !strcasecmp(optarg, "if-tty")) 1688131557Stjr color_option = 2; 1689131557Stjr else 1690131557Stjr show_help = 1; 1691131557Stjr } else 1692131557Stjr color_option = 2; 1693131557Stjr if(color_option == 2) { 1694131557Stjr if(isatty(STDOUT_FILENO) && getenv("TERM") && 1695131557Stjr strcmp(getenv("TERM"), "dumb")) 1696131557Stjr color_option = 1; 1697131557Stjr else 1698131557Stjr color_option = 0; 1699131557Stjr } 1700131557Stjr break; 1701131557Stjr 1702131557Stjr case EXCLUDE_OPTION: 1703131557Stjr if (!excluded_patterns) 1704131557Stjr excluded_patterns = new_exclude (); 1705131557Stjr add_exclude (excluded_patterns, optarg); 1706131557Stjr break; 1707131557Stjr 1708131557Stjr case EXCLUDE_FROM_OPTION: 1709131557Stjr if (!excluded_patterns) 1710131557Stjr excluded_patterns = new_exclude (); 1711131557Stjr if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n') 1712131557Stjr != 0) 1713131557Stjr { 1714131557Stjr error (2, errno, "%s", optarg); 1715131557Stjr } 1716131557Stjr break; 1717131557Stjr 1718131557Stjr case INCLUDE_OPTION: 1719131557Stjr if (!included_patterns) 1720131557Stjr included_patterns = new_exclude (); 1721131557Stjr add_exclude (included_patterns, optarg); 1722131557Stjr break; 1723131557Stjr 1724131557Stjr case LINE_BUFFERED_OPTION: 1725131557Stjr line_buffered = 1; 1726131557Stjr break; 1727131557Stjr 1728131557Stjr case LABEL_OPTION: 1729131557Stjr label = optarg; 1730131557Stjr break; 1731131557Stjr 173253477Sobrien case 0: 173353477Sobrien /* long options */ 173453477Sobrien break; 1735131557Stjr 173653451Speter default: 173753477Sobrien usage (2); 173853451Speter break; 1739131557Stjr 174053451Speter } 174153451Speter 1742131557Stjr /* POSIX.2 says that -q overrides -l, which in turn overrides the 1743131557Stjr other output options. */ 1744131557Stjr if (exit_on_match) 1745131557Stjr list_files = 0; 1746131557Stjr if (exit_on_match | list_files) 1747131557Stjr { 1748131557Stjr count_matches = 0; 1749131557Stjr done_on_match = 1; 1750131557Stjr } 1751131557Stjr out_quiet = count_matches | done_on_match; 1752131557Stjr 175353477Sobrien if (out_after < 0) 175453477Sobrien out_after = default_context; 175553477Sobrien if (out_before < 0) 175653477Sobrien out_before = default_context; 175753477Sobrien 1758131557Stjr if (color_option) 1759131557Stjr { 1760131557Stjr char *userval = getenv ("GREP_COLOR"); 1761131557Stjr if (userval != NULL && *userval != '\0') 1762131557Stjr grep_color = userval; 1763131557Stjr } 1764131557Stjr 176555379Sobrien if (! matcher) 1766131557Stjr matcher = program_name; 176755379Sobrien 176853477Sobrien if (show_version) 176953477Sobrien { 177055379Sobrien printf (_("%s (GNU grep) %s\n"), matcher, VERSION); 177153477Sobrien printf ("\n"); 177253477Sobrien printf (_("\ 1773131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n")); 177453477Sobrien printf (_("\ 177553477SobrienThis is free software; see the source for copying conditions. There is NO\n\ 177653477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")); 177753477Sobrien printf ("\n"); 177853477Sobrien exit (0); 177953477Sobrien } 178053477Sobrien 178153477Sobrien if (show_help) 178253477Sobrien usage (0); 178353477Sobrien 178453477Sobrien if (keys) 178553477Sobrien { 178653477Sobrien if (keycc == 0) 1787131557Stjr { 1788131557Stjr /* No keys were specified (e.g. -f /dev/null). Match nothing. */ 1789131557Stjr out_invert ^= 1; 1790131557Stjr match_lines = match_words = 0; 1791131557Stjr } 179253477Sobrien else 179353477Sobrien /* Strip trailing newline. */ 179453477Sobrien --keycc; 179553477Sobrien } 179653477Sobrien else 179753451Speter if (optind < argc) 179853451Speter { 179953451Speter keys = argv[optind++]; 180053477Sobrien keycc = strlen (keys); 180153451Speter } 180253451Speter else 180353477Sobrien usage (2); 180453451Speter 180555379Sobrien if (!install_matcher (matcher) && !install_matcher ("default")) 180653477Sobrien abort (); 180753451Speter 180853451Speter (*compile)(keys, keycc); 180953451Speter 181053477Sobrien if ((argc - optind > 1 && !no_filenames) || with_filenames) 181153451Speter out_file = 1; 181253451Speter 1813131557Stjr#ifdef SET_BINARY 181453477Sobrien /* Output is set to binary mode because we shouldn't convert 181553477Sobrien NL to CR-LF pairs, especially when grepping binary files. */ 181653477Sobrien if (!isatty (1)) 181753477Sobrien SET_BINARY (1); 181853451Speter#endif 181953451Speter 1820131557Stjr if (max_count == 0) 1821131557Stjr exit (1); 182253451Speter 182353451Speter if (optind < argc) 182453451Speter { 182553477Sobrien status = 1; 182653477Sobrien do 182753451Speter { 182853477Sobrien char *file = argv[optind]; 1829131557Stjr if ((included_patterns || excluded_patterns) 1830131557Stjr && !isdir (file)) 1831131557Stjr { 1832131557Stjr if (included_patterns && 1833131557Stjr ! excluded_filename (included_patterns, file, 0)) 1834131557Stjr continue; 1835131557Stjr if (excluded_patterns && 1836131557Stjr excluded_filename (excluded_patterns, file, 0)) 1837131557Stjr continue; 1838131557Stjr } 183953477Sobrien status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file, 184053477Sobrien &stats_base); 184153451Speter } 184253477Sobrien while ( ++optind < argc); 184353451Speter } 184453477Sobrien else 184553477Sobrien status = grepfile ((char *) NULL, &stats_base); 184653451Speter 1847131557Stjr /* We register via atexit() to test stdout. */ 184853477Sobrien exit (errseen ? 2 : status); 184953451Speter} 1850131557Stjr/* vim:set shiftwidth=2: */ 1851