grep.c revision 141847
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 141847 2005-02-13 23:07:30Z obrien $ */ 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)); 201131576Stjrstatic size_t (*execute) PARAMS ((char const *, size_t, struct mb_cache *, 202131576Stjr size_t *, int)); 20353477Sobrien 204131557Stjr/* Like error, but suppress the diagnostic if requested. */ 20553451Speterstatic void 206131557Stjrsuppressible_error (char const *mesg, int errnum) 20753451Speter{ 208131557Stjr if (! suppress_errors) 209131557Stjr error (0, errnum, "%s", mesg); 21053451Speter errseen = 1; 21153451Speter} 21253451Speter 21353477Sobrien/* Convert STR to a positive integer, storing the result in *OUT. 214131557Stjr STR must be a valid context length argument; report an error if it 215131557Stjr isn't. */ 216131557Stjrstatic void 217131557Stjrcontext_length_arg (char const *str, int *out) 21853477Sobrien{ 219131557Stjr uintmax_t value; 220131557Stjr if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK 221131557Stjr && 0 <= (*out = value) 222131557Stjr && *out == value)) 223131557Stjr { 224131557Stjr error (2, 0, "%s: %s\n", str, _("invalid context length argument")); 225131557Stjr } 22653477Sobrien} 22753477Sobrien 22853477Sobrien 22953451Speter/* Hairy buffering mechanism for grep. The intent is to keep 23053451Speter all reads aligned on a page boundary and multiples of the 231131557Stjr page size, unless a read yields a partial page. */ 23253451Speter 23353451Speterstatic char *buffer; /* Base of buffer. */ 234131557Stjrstatic size_t bufalloc; /* Allocated buffer size, counting slop. */ 235131557Stjr#define INITIAL_BUFSIZE 32768 /* Initial buffer size, not counting slop. */ 23653451Speterstatic int bufdesc; /* File descriptor. */ 23753451Speterstatic char *bufbeg; /* Beginning of user-visible stuff. */ 23853451Speterstatic char *buflim; /* Limit of user-visible stuff. */ 23953477Sobrienstatic size_t pagesize; /* alignment of memory pages */ 24055379Sobrienstatic off_t bufoffset; /* Read offset; defined on regular files. */ 241131557Stjrstatic off_t after_last_match; /* Pointer after last matching line that 242131557Stjr would have been output if we were 243131557Stjr outputting characters. */ 24453451Speter 24553477Sobrien#if defined(HAVE_MMAP) 24655379Sobrienstatic int bufmapped; /* True if buffer is memory-mapped. */ 24753477Sobrienstatic off_t initial_bufoffset; /* Initial value of bufoffset. */ 248131557Stjr#else 249131557Stjr# define bufmapped 0 25053451Speter#endif 25153451Speter 252103372Sobrien#include <bzlib.h> 253103372Sobrienstatic BZFILE* bzbufdesc; /* libbz2 file handle. */ 254103372Sobrienstatic int BZflag; /* uncompress before searching. */ 25553451Speter#if HAVE_LIBZ > 0 25653451Speter#include <zlib.h> 25753477Sobrienstatic gzFile gzbufdesc; /* zlib file descriptor. */ 25853477Sobrienstatic int Zflag; /* uncompress before searching. */ 25953451Speter#endif 26053451Speter 26153477Sobrien/* Return VAL aligned to the next multiple of ALIGNMENT. VAL can be 26253477Sobrien an integer or a pointer. Both args must be free of side effects. */ 26353477Sobrien#define ALIGN_TO(val, alignment) \ 26453477Sobrien ((size_t) (val) % (alignment) == 0 \ 26553477Sobrien ? (val) \ 26653477Sobrien : (val) + ((alignment) - (size_t) (val) % (alignment))) 26753477Sobrien 26853477Sobrien/* Reset the buffer for a new file, returning zero if we should skip it. 26953477Sobrien Initialize on the first time through. */ 27053477Sobrienstatic int 27156920Srureset (int fd, char const *file, struct stats *stats) 27253451Speter{ 273131557Stjr if (! pagesize) 27453451Speter { 27553477Sobrien pagesize = getpagesize (); 276131557Stjr if (pagesize == 0 || 2 * pagesize + 1 <= pagesize) 27753477Sobrien abort (); 278131557Stjr bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1; 279131557Stjr buffer = xmalloc (bufalloc); 28053451Speter } 281103372Sobrien if (BZflag) 282103372Sobrien { 283103372Sobrien bzbufdesc = BZ2_bzdopen(fd, "r"); 284103372Sobrien if (bzbufdesc == NULL) 285131557Stjr error(2, 0, _("memory exhausted")); 286103372Sobrien } 28753451Speter#if HAVE_LIBZ > 0 28855379Sobrien if (Zflag) 28955379Sobrien { 29053451Speter gzbufdesc = gzdopen(fd, "r"); 29153477Sobrien if (gzbufdesc == NULL) 292131557Stjr error(2, 0, _("memory exhausted")); 29355379Sobrien } 29453451Speter#endif 29555379Sobrien 296131557Stjr bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize); 297131557Stjr bufbeg[-1] = eolbyte; 29853477Sobrien bufdesc = fd; 29953477Sobrien 30055379Sobrien if (fstat (fd, &stats->stat) != 0) 30155379Sobrien { 302131557Stjr error (0, errno, "fstat"); 30355379Sobrien return 0; 30455379Sobrien } 30553477Sobrien if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode)) 30653477Sobrien return 0; 307131557Stjr#ifndef DJGPP 308131557Stjr if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode))) 309131557Stjr#else 310131557Stjr if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode))) 311131557Stjr#endif 312131557Stjr return 0; 31353477Sobrien if ( 314103372Sobrien BZflag || 31553451Speter#if HAVE_LIBZ > 0 31653477Sobrien Zflag || 31753451Speter#endif 31855379Sobrien S_ISREG (stats->stat.st_mode)) 31955379Sobrien { 32055379Sobrien if (file) 32155379Sobrien bufoffset = 0; 32255379Sobrien else 32355379Sobrien { 32455379Sobrien bufoffset = lseek (fd, 0, SEEK_CUR); 32555379Sobrien if (bufoffset < 0) 32655379Sobrien { 327131557Stjr error (0, errno, "lseek"); 32855379Sobrien return 0; 32955379Sobrien } 33055379Sobrien } 331131557Stjr#if defined(HAVE_MMAP) 33255379Sobrien initial_bufoffset = bufoffset; 33355379Sobrien bufmapped = mmap_option && bufoffset % pagesize == 0; 33455379Sobrien#endif 33555379Sobrien } 33653451Speter else 33753451Speter { 338131557Stjr#if defined(HAVE_MMAP) 33955379Sobrien bufmapped = 0; 34055379Sobrien#endif 34153451Speter } 34253477Sobrien return 1; 34353451Speter} 34453451Speter 34553451Speter/* Read new stuff into the buffer, saving the specified 34653451Speter amount of old stuff. When we're done, 'bufbeg' points 34753451Speter to the beginning of the buffer contents, and 'buflim' 34855379Sobrien points just after the end. Return zero if there's an error. */ 34953451Speterstatic int 350131557Stjrfillbuf (size_t save, struct stats const *stats) 35153451Speter{ 35255379Sobrien size_t fillsize = 0; 35355379Sobrien int cc = 1; 354131557Stjr char *readbuf; 35555379Sobrien size_t readsize; 35653451Speter 357131557Stjr /* Offset from start of buffer to start of old stuff 35855379Sobrien that we want to save. */ 359131557Stjr size_t saved_offset = buflim - save - buffer; 36055379Sobrien 361131557Stjr if (pagesize <= buffer + bufalloc - buflim) 36253451Speter { 363131557Stjr readbuf = buflim; 364131557Stjr bufbeg = buflim - save; 365131557Stjr } 366131557Stjr else 367131557Stjr { 368131557Stjr size_t minsize = save + pagesize; 369131557Stjr size_t newsize; 37055379Sobrien size_t newalloc; 371131557Stjr char *newbuf; 37253477Sobrien 373131557Stjr /* Grow newsize until it is at least as great as minsize. */ 374131557Stjr for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2) 375131557Stjr if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2) 376131557Stjr xalloc_die (); 377131557Stjr 378131557Stjr /* Try not to allocate more memory than the file size indicates, 379131557Stjr as that might cause unnecessary memory exhaustion if the file 380131557Stjr is large. However, do not use the original file size as a 381131557Stjr heuristic if we've already read past the file end, as most 382131557Stjr likely the file is growing. */ 38355379Sobrien if (S_ISREG (stats->stat.st_mode)) 38455379Sobrien { 38555379Sobrien off_t to_be_read = stats->stat.st_size - bufoffset; 386131557Stjr off_t maxsize_off = save + to_be_read; 387131557Stjr if (0 <= to_be_read && to_be_read <= maxsize_off 388131557Stjr && maxsize_off == (size_t) maxsize_off 389131557Stjr && minsize <= (size_t) maxsize_off 390131557Stjr && (size_t) maxsize_off < newsize) 391131557Stjr newsize = maxsize_off; 39255379Sobrien } 39355379Sobrien 394131557Stjr /* Add enough room so that the buffer is aligned and has room 395131557Stjr for byte sentinels fore and aft. */ 396131557Stjr newalloc = newsize + pagesize + 1; 39755379Sobrien 398131557Stjr newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer; 399131557Stjr readbuf = ALIGN_TO (newbuf + 1 + save, pagesize); 400131557Stjr bufbeg = readbuf - save; 401131557Stjr memmove (bufbeg, buffer + saved_offset, save); 402131557Stjr bufbeg[-1] = eolbyte; 403131557Stjr if (newbuf != buffer) 40455379Sobrien { 405131557Stjr free (buffer); 406131557Stjr buffer = newbuf; 40755379Sobrien } 40853451Speter } 40953451Speter 410131557Stjr readsize = buffer + bufalloc - readbuf; 411131557Stjr readsize -= readsize % pagesize; 41255379Sobrien 41353477Sobrien#if defined(HAVE_MMAP) 41455379Sobrien if (bufmapped) 41553451Speter { 41655379Sobrien size_t mmapsize = readsize; 41755379Sobrien 41855379Sobrien /* Don't mmap past the end of the file; some hosts don't allow this. 41955379Sobrien Use `read' on the last page. */ 42055379Sobrien if (stats->stat.st_size - bufoffset < mmapsize) 42153451Speter { 42255379Sobrien mmapsize = stats->stat.st_size - bufoffset; 42355379Sobrien mmapsize -= mmapsize % pagesize; 42453451Speter } 42555379Sobrien 42655379Sobrien if (mmapsize 427131557Stjr && (mmap ((caddr_t) readbuf, mmapsize, 42855379Sobrien PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 42955379Sobrien bufdesc, bufoffset) 43055379Sobrien != (caddr_t) -1)) 43153451Speter { 43255379Sobrien /* Do not bother to use madvise with MADV_SEQUENTIAL or 43355379Sobrien MADV_WILLNEED on the mmapped memory. One might think it 43455379Sobrien would help, but it slows us down about 30% on SunOS 4.1. */ 43555379Sobrien fillsize = mmapsize; 43655379Sobrien } 43755379Sobrien else 43855379Sobrien { 43955379Sobrien /* Stop using mmap on this file. Synchronize the file 44055379Sobrien offset. Do not warn about mmap failures. On some hosts 44155379Sobrien (e.g. Solaris 2.5) mmap can fail merely because some 44255379Sobrien other process has an advisory read lock on the file. 44355379Sobrien There's no point alarming the user about this misfeature. */ 44453451Speter bufmapped = 0; 44555379Sobrien if (bufoffset != initial_bufoffset 44655379Sobrien && lseek (bufdesc, bufoffset, SEEK_SET) < 0) 44755379Sobrien { 448131557Stjr error (0, errno, "lseek"); 44955379Sobrien cc = 0; 45055379Sobrien } 45153451Speter } 45255379Sobrien } 45355379Sobrien#endif /*HAVE_MMAP*/ 45455379Sobrien 45555379Sobrien if (! fillsize) 45655379Sobrien { 45755379Sobrien ssize_t bytesread; 45855379Sobrien do 459104555Sobrien if (BZflag && bzbufdesc) 460103372Sobrien { 461104555Sobrien int bzerr; 462131557Stjr bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize); 463104555Sobrien 464104555Sobrien switch (bzerr) 465104555Sobrien { 466104555Sobrien case BZ_OK: 467104555Sobrien case BZ_STREAM_END: 468104555Sobrien /* ok */ 469104555Sobrien break; 470104555Sobrien case BZ_DATA_ERROR_MAGIC: 471104555Sobrien BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL; 472104555Sobrien lseek (bufdesc, 0, SEEK_SET); 473131557Stjr bytesread = read (bufdesc, readbuf, readsize); 474104555Sobrien break; 475104555Sobrien default: 476104555Sobrien bytesread = 0; 477104555Sobrien break; 478104555Sobrien } 479103372Sobrien } 480103372Sobrien else 48153451Speter#if HAVE_LIBZ > 0 48255379Sobrien if (Zflag) 483131557Stjr bytesread = gzread (gzbufdesc, readbuf, readsize); 48455379Sobrien else 48555379Sobrien#endif 486131557Stjr bytesread = read (bufdesc, readbuf, readsize); 48755379Sobrien while (bytesread < 0 && errno == EINTR); 48855379Sobrien if (bytesread < 0) 48955379Sobrien cc = 0; 49053477Sobrien else 49155379Sobrien fillsize = bytesread; 49253451Speter } 49355379Sobrien 49455379Sobrien bufoffset += fillsize; 495131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 49655379Sobrien if (fillsize) 497131557Stjr fillsize = undossify_input (readbuf, fillsize); 49853451Speter#endif 499131557Stjr buflim = readbuf + fillsize; 50053451Speter return cc; 50153451Speter} 50253451Speter 50353451Speter/* Flags controlling the style of output. */ 50456233Srustatic enum 505131557Stjr{ 506131557Stjr BINARY_BINARY_FILES, 507131557Stjr TEXT_BINARY_FILES, 508131557Stjr WITHOUT_MATCH_BINARY_FILES 509131557Stjr} binary_files; /* How to handle binary files. */ 510131557Stjr 511131557Stjrstatic int filename_mask; /* If zero, output nulls after filenames. */ 51253451Speterstatic int out_quiet; /* Suppress all normal output. */ 51353451Speterstatic int out_invert; /* Print nonmatching stuff. */ 51453451Speterstatic int out_file; /* Print filenames. */ 51553451Speterstatic int out_line; /* Print line numbers. */ 51653451Speterstatic int out_byte; /* Print byte offsets. */ 51753451Speterstatic int out_before; /* Lines of leading context. */ 51853451Speterstatic int out_after; /* Lines of trailing context. */ 51953477Sobrienstatic int count_matches; /* Count matching lines. */ 52053477Sobrienstatic int list_files; /* List matching files. */ 52153477Sobrienstatic int no_filenames; /* Suppress file names. */ 522131557Stjrstatic off_t max_count; /* Stop after outputting this many 523131557Stjr lines from an input file. */ 524131557Stjrstatic int line_buffered; /* If nonzero, use line buffering, i.e. 525131557Stjr fflush everyline out. */ 526131557Stjrstatic char *label = NULL; /* Fake filename for stdin */ 52753451Speter 528131557Stjr 52953451Speter/* Internal variables to keep track of byte count, context, etc. */ 530131557Stjrstatic uintmax_t totalcc; /* Total character count before bufbeg. */ 531131557Stjrstatic char const *lastnl; /* Pointer after last newline counted. */ 532131557Stjrstatic char const *lastout; /* Pointer after last character output; 53353451Speter NULL if no character has been output 53453451Speter or if it's conceptually before bufbeg. */ 535131557Stjrstatic uintmax_t totalnl; /* Total newline count before lastnl. */ 536131557Stjrstatic off_t outleft; /* Maximum number of lines to be output. */ 537131557Stjrstatic int pending; /* Pending lines of output. 538131557Stjr Always kept 0 if out_quiet is true. */ 539131557Stjrstatic int done_on_match; /* Stop scanning file on first match. */ 540131557Stjrstatic int exit_on_match; /* Exit on first match. */ 54153451Speter 542131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 54353477Sobrien# include "dosbuf.c" 54453477Sobrien#endif 54553477Sobrien 546131557Stjr/* Add two numbers that count input bytes or lines, and report an 547131557Stjr error if the addition overflows. */ 548131557Stjrstatic uintmax_t 549131557Stjradd_count (uintmax_t a, uintmax_t b) 550131557Stjr{ 551131557Stjr uintmax_t sum = a + b; 552131557Stjr if (sum < a) 553131557Stjr error (2, 0, _("input is too large to count")); 554131557Stjr return sum; 555131557Stjr} 556131557Stjr 55753451Speterstatic void 558131557Stjrnlscan (char const *lim) 55953451Speter{ 560131557Stjr size_t newlines = 0; 561131557Stjr char const *beg; 562131557Stjr for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++) 563131557Stjr newlines++; 564131557Stjr totalnl = add_count (totalnl, newlines); 56555379Sobrien lastnl = lim; 56653451Speter} 56753451Speter 568131557Stjr/* Print a byte offset, followed by a character separator. */ 56953451Speterstatic void 570131557Stjrprint_offset_sep (uintmax_t pos, char sep) 57153477Sobrien{ 572131557Stjr /* Do not rely on printf to print pos, since uintmax_t may be longer 573131557Stjr than long, and long long is not portable. */ 57453477Sobrien 57553477Sobrien char buf[sizeof pos * CHAR_BIT]; 57653477Sobrien char *p = buf + sizeof buf - 1; 57753477Sobrien *p = sep; 57853477Sobrien 57953477Sobrien do 58053477Sobrien *--p = '0' + pos % 10; 58153477Sobrien while ((pos /= 10) != 0); 58253477Sobrien 58353477Sobrien fwrite (p, 1, buf + sizeof buf - p, stdout); 58453477Sobrien} 58553477Sobrien 58653477Sobrienstatic void 587131576Stjrprline (char const *beg, char const *lim, int sep, struct mb_cache *mb_cache) 58853451Speter{ 58953451Speter if (out_file) 59055379Sobrien printf ("%s%c", filename, sep & filename_mask); 59153451Speter if (out_line) 59253451Speter { 59353477Sobrien nlscan (beg); 594131557Stjr totalnl = add_count (totalnl, 1); 595131557Stjr print_offset_sep (totalnl, sep); 59653451Speter lastnl = lim; 59753451Speter } 59853451Speter if (out_byte) 59953477Sobrien { 600131557Stjr uintmax_t pos = add_count (totalcc, beg - bufbeg); 601131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 60253477Sobrien pos = dossified_pos (pos); 60353477Sobrien#endif 60453477Sobrien print_offset_sep (pos, sep); 60553477Sobrien } 606131557Stjr if (only_matching) 607131557Stjr { 608131557Stjr size_t match_size; 609131557Stjr size_t match_offset; 610131576Stjr while ((match_offset = (*execute) (beg, lim - beg, mb_cache, 611131576Stjr &match_size, 1)) 612131557Stjr != (size_t) -1) 613131557Stjr { 614131557Stjr char const *b = beg + match_offset; 615131557Stjr if (b == lim) 616131557Stjr break; 617131557Stjr if (match_size == 0) 618131557Stjr break; 619131557Stjr if(color_option) 620131557Stjr printf("\33[%sm", grep_color); 621131557Stjr fwrite(b, sizeof (char), match_size, stdout); 622131557Stjr if(color_option) 623131557Stjr fputs("\33[00m", stdout); 624131557Stjr fputs("\n", stdout); 625131557Stjr beg = b + match_size; 626131557Stjr } 627131557Stjr lastout = lim; 628131557Stjr if(line_buffered) 629131557Stjr fflush(stdout); 630131557Stjr return; 631131557Stjr } 632131557Stjr if (color_option) 633131557Stjr { 634131557Stjr size_t match_size; 635131557Stjr size_t match_offset; 636131557Stjr if(match_icase) 637131557Stjr { 638131557Stjr /* Yuck, this is tricky */ 639131557Stjr char *buf = (char*) xmalloc (lim - beg); 640131557Stjr char *ibeg = buf; 641131557Stjr char *ilim = ibeg + (lim - beg); 642131557Stjr int i; 643131557Stjr for (i = 0; i < lim - beg; i++) 644131557Stjr ibeg[i] = tolower (beg[i]); 645131576Stjr while ((match_offset = (*execute) (ibeg, ilim-ibeg, mb_cache, 646131576Stjr &match_size, 1)) 647131557Stjr != (size_t) -1) 648131557Stjr { 649131557Stjr char const *b = beg + match_offset; 650131557Stjr if (b == lim) 651131557Stjr break; 652131557Stjr fwrite (beg, sizeof (char), match_offset, stdout); 653131557Stjr printf ("\33[%sm", grep_color); 654131557Stjr fwrite (b, sizeof (char), match_size, stdout); 655131557Stjr fputs ("\33[00m", stdout); 656131557Stjr beg = b + match_size; 657131557Stjr ibeg = ibeg + match_offset + match_size; 658131557Stjr } 659131557Stjr fwrite (beg, 1, lim - beg, stdout); 660131557Stjr free (buf); 661131557Stjr lastout = lim; 662131557Stjr return; 663131557Stjr } 664131576Stjr while (lim-beg && (match_offset = (*execute) (beg, lim - beg, mb_cache, 665131576Stjr &match_size, 1)) 666131557Stjr != (size_t) -1) 667131557Stjr { 668131557Stjr char const *b = beg + match_offset; 669131557Stjr /* Avoid matching the empty line at the end of the buffer. */ 670131557Stjr if (b == lim) 671131557Stjr break; 672131557Stjr /* Avoid hanging on grep --color "" foo */ 673131557Stjr if (match_size == 0) 674131557Stjr break; 675131557Stjr fwrite (beg, sizeof (char), match_offset, stdout); 676131557Stjr printf ("\33[%sm", grep_color); 677131557Stjr fwrite (b, sizeof (char), match_size, stdout); 678131557Stjr fputs ("\33[00m", stdout); 679131557Stjr beg = b + match_size; 680131557Stjr } 681131557Stjr } 68253477Sobrien fwrite (beg, 1, lim - beg, stdout); 68353477Sobrien if (ferror (stdout)) 684131557Stjr error (0, errno, _("writing output")); 68553451Speter lastout = lim; 686131557Stjr if (line_buffered) 687131557Stjr fflush (stdout); 68853451Speter} 68953451Speter 690131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends 691131557Stjr at the next matching line when OUTLEFT is 0. */ 69253451Speterstatic void 693131576Stjrprpending (char const *lim, struct mb_cache *mb_cache) 69453451Speter{ 69553451Speter if (!lastout) 69653451Speter lastout = bufbeg; 69753451Speter while (pending > 0 && lastout < lim) 69853451Speter { 699131557Stjr char const *nl = memchr (lastout, eolbyte, lim - lastout); 700131557Stjr size_t match_size; 70153451Speter --pending; 702131557Stjr if (outleft 703131576Stjr || (((*execute) (lastout, nl - lastout, mb_cache, 704131576Stjr &match_size, 0) == (size_t) -1) 705131557Stjr == !out_invert)) 706131576Stjr prline (lastout, nl + 1, '-', mb_cache); 70753451Speter else 708131557Stjr pending = 0; 70953451Speter } 71053451Speter} 71153451Speter 71253451Speter/* Print the lines between BEG and LIM. Deal with context crap. 713131557Stjr If NLINESP is non-null, store a count of lines between BEG and LIM. */ 71453451Speterstatic void 715131576Stjrprtext (char const *beg, char const *lim, int *nlinesp, 716131576Stjr struct mb_cache *mb_cache) 71753451Speter{ 71853451Speter static int used; /* avoid printing "--" before any output */ 719131557Stjr char const *bp, *p; 72055379Sobrien char eol = eolbyte; 72153451Speter int i, n; 72253451Speter 72353451Speter if (!out_quiet && pending > 0) 724131576Stjr prpending (beg, mb_cache); 72553451Speter 72653451Speter p = beg; 72753451Speter 72853451Speter if (!out_quiet) 72953451Speter { 73053451Speter /* Deal with leading context crap. */ 73153451Speter 73253451Speter bp = lastout ? lastout : bufbeg; 73353451Speter for (i = 0; i < out_before; ++i) 73453451Speter if (p > bp) 73553451Speter do 73653451Speter --p; 737131557Stjr while (p[-1] != eol); 73853451Speter 73953451Speter /* We only print the "--" separator if our output is 74053451Speter discontiguous from the last output in the file. */ 74153451Speter if ((out_before || out_after) && used && p != lastout) 74253477Sobrien puts ("--"); 74353451Speter 74453451Speter while (p < beg) 74553451Speter { 746131557Stjr char const *nl = memchr (p, eol, beg - p); 747131557Stjr nl++; 748131576Stjr prline (p, nl, '-', mb_cache); 749131557Stjr p = nl; 75053451Speter } 75153451Speter } 75253451Speter 75353451Speter if (nlinesp) 75453451Speter { 75553451Speter /* Caller wants a line count. */ 756131557Stjr for (n = 0; p < lim && n < outleft; n++) 75753451Speter { 758131557Stjr char const *nl = memchr (p, eol, lim - p); 759131557Stjr nl++; 76053451Speter if (!out_quiet) 761131576Stjr prline (p, nl, ':', mb_cache); 76253451Speter p = nl; 76353451Speter } 76453451Speter *nlinesp = n; 765131557Stjr 766131557Stjr /* relying on it that this function is never called when outleft = 0. */ 767131557Stjr after_last_match = bufoffset - (buflim - p); 76853451Speter } 76953451Speter else 77053451Speter if (!out_quiet) 771131576Stjr prline (beg, lim, ':', mb_cache); 77253451Speter 77355379Sobrien pending = out_quiet ? 0 : out_after; 77453451Speter used = 1; 77553451Speter} 77653451Speter 77753451Speter/* Scan the specified portion of the buffer, matching lines (or 77853451Speter between matching lines if OUT_INVERT is true). Return a count of 77953451Speter lines printed. */ 78053451Speterstatic int 781131576Stjrgrepbuf (char const *beg, char const *lim, struct mb_cache *mb_cache) 78253451Speter{ 78353451Speter int nlines, n; 784131557Stjr register char const *p; 785131557Stjr size_t match_offset; 786131557Stjr size_t match_size; 78753451Speter 78853451Speter nlines = 0; 78953451Speter p = beg; 790131576Stjr while ((match_offset = (*execute) (p, lim - p, mb_cache, 791131576Stjr &match_size, 0)) != (size_t) -1) 79253451Speter { 793131557Stjr char const *b = p + match_offset; 794131557Stjr char const *endp = b + match_size; 79553451Speter /* Avoid matching the empty line at the end of the buffer. */ 796131557Stjr if (b == lim) 79753451Speter break; 79853451Speter if (!out_invert) 79953451Speter { 800131576Stjr prtext (b, endp, (int *) 0, mb_cache); 801131557Stjr nlines++; 802131557Stjr outleft--; 803131557Stjr if (!outleft || done_on_match) 804131557Stjr { 805131557Stjr if (exit_on_match) 806131557Stjr exit (0); 807131557Stjr after_last_match = bufoffset - (buflim - endp); 808131557Stjr return nlines; 809131557Stjr } 81053451Speter } 81153451Speter else if (p < b) 81253451Speter { 813131576Stjr prtext (p, b, &n, mb_cache); 81453451Speter nlines += n; 815131557Stjr outleft -= n; 816131557Stjr if (!outleft) 817131557Stjr return nlines; 81853451Speter } 81953451Speter p = endp; 82053451Speter } 82153451Speter if (out_invert && p < lim) 82253451Speter { 823131576Stjr prtext (p, lim, &n, mb_cache); 82453451Speter nlines += n; 825131557Stjr outleft -= n; 82653451Speter } 82753451Speter return nlines; 82853451Speter} 82953451Speter 83053477Sobrien/* Search a given file. Normally, return a count of lines printed; 83153477Sobrien but if the file is a directory and we search it recursively, then 83253477Sobrien return -2 if there was a match, and -1 otherwise. */ 83353451Speterstatic int 83456920Srugrep (int fd, char const *file, struct stats *stats) 83553451Speter{ 83653451Speter int nlines, i; 83753477Sobrien int not_text; 83853451Speter size_t residue, save; 839131557Stjr char oldc; 840131557Stjr char *beg; 841131557Stjr char *lim; 84255379Sobrien char eol = eolbyte; 843131576Stjr struct mb_cache mb_cache; 84453451Speter 845131576Stjr memset (&mb_cache, 0, sizeof (mb_cache)); 84653477Sobrien if (!reset (fd, file, stats)) 84753477Sobrien return 0; 84853451Speter 84953477Sobrien if (file && directories == RECURSE_DIRECTORIES 85053477Sobrien && S_ISDIR (stats->stat.st_mode)) 85153477Sobrien { 85253477Sobrien /* Close fd now, so that we don't open a lot of file descriptors 85353477Sobrien when we recurse deeply. */ 854104555Sobrien if (BZflag && bzbufdesc) 855103372Sobrien BZ2_bzclose(bzbufdesc); 856103372Sobrien else 85753477Sobrien#if HAVE_LIBZ > 0 85853477Sobrien if (Zflag) 85953477Sobrien gzclose(gzbufdesc); 86053477Sobrien else 86153477Sobrien#endif 86253477Sobrien if (close (fd) != 0) 863131557Stjr error (0, errno, "%s", file); 86453477Sobrien return grepdir (file, stats) - 2; 86553477Sobrien } 86653477Sobrien 86753451Speter totalcc = 0; 86853451Speter lastout = 0; 86953451Speter totalnl = 0; 870131557Stjr outleft = max_count; 871131557Stjr after_last_match = 0; 87253451Speter pending = 0; 87353451Speter 87453451Speter nlines = 0; 87553451Speter residue = 0; 87653451Speter save = 0; 87753451Speter 87855379Sobrien if (! fillbuf (save, stats)) 87953451Speter { 880131557Stjr if (! is_EISDIR (errno, file)) 881131557Stjr suppressible_error (filename, errno); 88256233Sru return 0; 88353477Sobrien } 88453451Speter 88556233Sru not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet) 88656233Sru || binary_files == WITHOUT_MATCH_BINARY_FILES) 88755379Sobrien && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg)); 88856233Sru if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES) 88956233Sru return 0; 89053477Sobrien done_on_match += not_text; 89153477Sobrien out_quiet += not_text; 89253451Speter 89353477Sobrien for (;;) 89453477Sobrien { 89553451Speter lastnl = bufbeg; 89653451Speter if (lastout) 89753451Speter lastout = bufbeg; 898131557Stjr 899131557Stjr beg = bufbeg + save; 900131557Stjr 901131557Stjr /* no more data to scan (eof) except for maybe a residue -> break */ 902131557Stjr if (beg == buflim) 90353451Speter break; 904131557Stjr 905131557Stjr /* Determine new residue (the length of an incomplete line at the end of 906131557Stjr the buffer, 0 means there is no incomplete last line). */ 907131557Stjr oldc = beg[-1]; 908131557Stjr beg[-1] = eol; 909131557Stjr for (lim = buflim; lim[-1] != eol; lim--) 910131557Stjr continue; 911131557Stjr beg[-1] = oldc; 912131557Stjr if (lim == beg) 913131557Stjr lim = beg - residue; 914131557Stjr beg -= residue; 91553451Speter residue = buflim - lim; 916131557Stjr 91753451Speter if (beg < lim) 91853451Speter { 919131557Stjr if (outleft) 920131576Stjr nlines += grepbuf (beg, lim, &mb_cache); 92153451Speter if (pending) 922131576Stjr prpending (lim, &mb_cache); 923131557Stjr if((!outleft && !pending) || (nlines && done_on_match && !out_invert)) 92453477Sobrien goto finish_grep; 92553451Speter } 926131557Stjr 927131557Stjr /* The last OUT_BEFORE lines at the end of the buffer will be needed as 928131557Stjr leading context if there is a matching line at the begin of the 929131557Stjr next data. Make beg point to their begin. */ 93053451Speter i = 0; 93153451Speter beg = lim; 93253451Speter while (i < out_before && beg > bufbeg && beg != lastout) 93353451Speter { 93453451Speter ++i; 93553451Speter do 93653451Speter --beg; 937131557Stjr while (beg[-1] != eol); 93853451Speter } 939131557Stjr 940131557Stjr /* detect if leading context is discontinuous from last printed line. */ 94153451Speter if (beg != lastout) 94253451Speter lastout = 0; 943131557Stjr 944131557Stjr /* Handle some details and read more data to scan. */ 94553451Speter save = residue + lim - beg; 946131557Stjr if (out_byte) 947131557Stjr totalcc = add_count (totalcc, buflim - bufbeg - save); 94853451Speter if (out_line) 94953477Sobrien nlscan (beg); 950131576Stjr if (mb_cache.wcs_buf) 951131576Stjr free (mb_cache.wcs_buf); 952131576Stjr if (mb_cache.mblen_buf) 953131576Stjr free (mb_cache.mblen_buf); 954131576Stjr memset (&mb_cache, 0, sizeof (mb_cache)); 95555379Sobrien if (! fillbuf (save, stats)) 95653477Sobrien { 957131557Stjr if (! is_EISDIR (errno, file)) 958131557Stjr suppressible_error (filename, errno); 95953477Sobrien goto finish_grep; 96053477Sobrien } 96153451Speter } 96253451Speter if (residue) 96353451Speter { 96456920Sru *buflim++ = eol; 965131557Stjr if (outleft) 966131576Stjr nlines += grepbuf (bufbeg + save - residue, buflim, &mb_cache); 96753451Speter if (pending) 968131576Stjr prpending (buflim, &mb_cache); 96953451Speter } 97053477Sobrien 97153477Sobrien finish_grep: 97253477Sobrien done_on_match -= not_text; 97353477Sobrien out_quiet -= not_text; 97453477Sobrien if ((not_text & ~out_quiet) && nlines != 0) 97553477Sobrien printf (_("Binary file %s matches\n"), filename); 976131576Stjr 977131576Stjr if (mb_cache.wcs_buf) 978131576Stjr free (mb_cache.wcs_buf); 979131576Stjr if (mb_cache.mblen_buf) 980131576Stjr free (mb_cache.mblen_buf); 98153451Speter return nlines; 98253451Speter} 98353451Speter 98453477Sobrienstatic int 98556920Srugrepfile (char const *file, struct stats *stats) 98653477Sobrien{ 98753477Sobrien int desc; 98853477Sobrien int count; 98953477Sobrien int status; 99053477Sobrien 99153477Sobrien if (! file) 99253477Sobrien { 99353477Sobrien desc = 0; 994131557Stjr filename = label ? label : _("(standard input)"); 99553477Sobrien } 99653477Sobrien else 99753477Sobrien { 99855379Sobrien while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR) 99955379Sobrien continue; 100053477Sobrien 100153477Sobrien if (desc < 0) 100253477Sobrien { 100353477Sobrien int e = errno; 1004131557Stjr 100553477Sobrien if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES) 100653477Sobrien { 100753477Sobrien if (stat (file, &stats->stat) != 0) 100853477Sobrien { 1009131557Stjr error (0, errno, "%s", file); 101053477Sobrien return 1; 101153477Sobrien } 101253477Sobrien 101353477Sobrien return grepdir (file, stats); 101453477Sobrien } 1015131557Stjr 101653477Sobrien if (!suppress_errors) 101753477Sobrien { 101853477Sobrien if (directories == SKIP_DIRECTORIES) 101953477Sobrien switch (e) 102053477Sobrien { 1021131557Stjr#if defined(EISDIR) 102253477Sobrien case EISDIR: 102353477Sobrien return 1; 102453451Speter#endif 102553477Sobrien case EACCES: 102653477Sobrien /* When skipping directories, don't worry about 102753477Sobrien directories that can't be opened. */ 1028131557Stjr if (isdir (file)) 102953477Sobrien return 1; 103053477Sobrien break; 103153477Sobrien } 103253477Sobrien } 103353477Sobrien 1034131557Stjr suppressible_error (file, e); 103553477Sobrien return 1; 103653477Sobrien } 103753477Sobrien 103853477Sobrien filename = file; 103953477Sobrien } 104053477Sobrien 1041131557Stjr#if defined(SET_BINARY) 104253477Sobrien /* Set input to binary mode. Pipes are simulated with files 104353477Sobrien on DOS, so this includes the case of "foo | grep bar". */ 104453477Sobrien if (!isatty (desc)) 104553477Sobrien SET_BINARY (desc); 104653477Sobrien#endif 104753477Sobrien 104853477Sobrien count = grep (desc, file, stats); 104953477Sobrien if (count < 0) 105053477Sobrien status = count + 2; 105153477Sobrien else 105253477Sobrien { 105353477Sobrien if (count_matches) 105453477Sobrien { 105553477Sobrien if (out_file) 105655379Sobrien printf ("%s%c", filename, ':' & filename_mask); 105753477Sobrien printf ("%d\n", count); 105853477Sobrien } 105953477Sobrien 106055379Sobrien status = !count; 106155379Sobrien if (list_files == 1 - 2 * status) 106255379Sobrien printf ("%s%c", filename, '\n' & filename_mask); 106353477Sobrien 1064104555Sobrien if (BZflag && bzbufdesc) 1065103372Sobrien BZ2_bzclose(bzbufdesc); 1066103372Sobrien else 106753451Speter#if HAVE_LIBZ > 0 106853477Sobrien if (Zflag) 106953477Sobrien gzclose(gzbufdesc); 107053477Sobrien else 107153451Speter#endif 1072131557Stjr if (! file) 1073131557Stjr { 1074131557Stjr off_t required_offset = outleft ? bufoffset : after_last_match; 1075131557Stjr if ((bufmapped || required_offset != bufoffset) 1076131557Stjr && lseek (desc, required_offset, SEEK_SET) < 0 1077131557Stjr && S_ISREG (stats->stat.st_mode)) 1078131557Stjr error (0, errno, "%s", filename); 1079131557Stjr } 1080131557Stjr else 108155379Sobrien while (close (desc) != 0) 108255379Sobrien if (errno != EINTR) 108355379Sobrien { 1084131557Stjr error (0, errno, "%s", file); 108555379Sobrien break; 108655379Sobrien } 108753477Sobrien } 108853451Speter 108953477Sobrien return status; 109053477Sobrien} 109153477Sobrien 109253477Sobrienstatic int 1093131557Stjrgrepdir (char const *dir, struct stats const *stats) 109453477Sobrien{ 109553477Sobrien int status = 1; 1096131557Stjr struct stats const *ancestor; 109753477Sobrien char *name_space; 109853477Sobrien 1099131557Stjr /* Mingw32 does not support st_ino. No known working hosts use zero 1100131557Stjr for st_ino, so assume that the Mingw32 bug applies if it's zero. */ 1101131557Stjr if (stats->stat.st_ino) 1102131557Stjr for (ancestor = stats; (ancestor = ancestor->parent) != 0; ) 1103131557Stjr if (ancestor->stat.st_ino == stats->stat.st_ino 1104131557Stjr && ancestor->stat.st_dev == stats->stat.st_dev) 1105131557Stjr { 1106131557Stjr if (!suppress_errors) 1107141847Sobrien error (0, 0, _("warning: %s: %s"), dir, 110853477Sobrien _("recursive directory loop")); 1109131557Stjr return 1; 1110131557Stjr } 111153477Sobrien 1112131557Stjr name_space = savedir (dir, stats->stat.st_size, included_patterns, 1113131557Stjr excluded_patterns); 111453477Sobrien 111553477Sobrien if (! name_space) 111653477Sobrien { 111753477Sobrien if (errno) 1118131557Stjr suppressible_error (dir, errno); 111953477Sobrien else 1120131557Stjr xalloc_die (); 112153477Sobrien } 112253477Sobrien else 112353477Sobrien { 112453477Sobrien size_t dirlen = strlen (dir); 112553477Sobrien int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir) 112653477Sobrien || IS_SLASH (dir[dirlen - 1])); 112753477Sobrien char *file = NULL; 1128131557Stjr char const *namep = name_space; 112953477Sobrien struct stats child; 113053477Sobrien child.parent = stats; 113153477Sobrien out_file += !no_filenames; 113253477Sobrien while (*namep) 113353477Sobrien { 113453477Sobrien size_t namelen = strlen (namep); 113553477Sobrien file = xrealloc (file, dirlen + 1 + namelen + 1); 113653477Sobrien strcpy (file, dir); 113753477Sobrien file[dirlen] = '/'; 113853477Sobrien strcpy (file + dirlen + needs_slash, namep); 113953477Sobrien namep += namelen + 1; 114053477Sobrien status &= grepfile (file, &child); 114153477Sobrien } 114253477Sobrien out_file -= !no_filenames; 114353477Sobrien if (file) 114453477Sobrien free (file); 114553477Sobrien free (name_space); 114653477Sobrien } 114753477Sobrien 114853477Sobrien return status; 114953477Sobrien} 115053477Sobrien 115153451Speterstatic void 115256920Sruusage (int status) 115353451Speter{ 115453477Sobrien if (status != 0) 115553477Sobrien { 1156131557Stjr fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"), 1157131557Stjr program_name); 1158131557Stjr fprintf (stderr, _("Try `%s --help' for more information.\n"), 1159131557Stjr program_name); 116053477Sobrien } 116153477Sobrien else 116253477Sobrien { 1163131557Stjr printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name); 116453477Sobrien printf (_("\ 116553477SobrienSearch for PATTERN in each FILE or standard input.\n\ 116656920SruExample: %s -i 'hello world' menu.h main.c\n\ 116753477Sobrien\n\ 1168131557StjrRegexp selection and interpretation:\n"), program_name); 116955379Sobrien printf (_("\ 117053477Sobrien -E, --extended-regexp PATTERN is an extended regular expression\n\ 117155379Sobrien -F, --fixed-strings PATTERN is a set of newline-separated strings\n\ 1172131557Stjr -G, --basic-regexp PATTERN is a basic regular expression\n\ 1173131557Stjr -P, --perl-regexp PATTERN is a Perl regular expression\n")); 117455379Sobrien printf (_("\ 117553477Sobrien -e, --regexp=PATTERN use PATTERN as a regular expression\n\ 117653477Sobrien -f, --file=FILE obtain PATTERN from FILE\n\ 117753477Sobrien -i, --ignore-case ignore case distinctions\n\ 117853477Sobrien -w, --word-regexp force PATTERN to match only whole words\n\ 117955379Sobrien -x, --line-regexp force PATTERN to match only whole lines\n\ 118055379Sobrien -z, --null-data a data line ends in 0 byte, not newline\n")); 118153477Sobrien printf (_("\ 118253477Sobrien\n\ 118353477SobrienMiscellaneous:\n\ 118453477Sobrien -s, --no-messages suppress error messages\n\ 118555379Sobrien -v, --invert-match select non-matching lines\n\ 118653477Sobrien -V, --version print version information and exit\n\ 118755379Sobrien --help display this help and exit\n\ 1188103372Sobrien -J, --bz2decompress decompress bzip2'ed input before searching\n\ 118953477Sobrien -Z, --decompress decompress input before searching (HAVE_LIBZ=1)\n\ 119055379Sobrien --mmap use memory-mapped input if possible\n")); 119153477Sobrien printf (_("\ 119253477Sobrien\n\ 119353477SobrienOutput control:\n\ 1194131557Stjr -m, --max-count=NUM stop after NUM matches\n\ 119553477Sobrien -b, --byte-offset print the byte offset with output lines\n\ 119653477Sobrien -n, --line-number print line number with output lines\n\ 1197131557Stjr --line-buffered flush output on every line\n\ 119853477Sobrien -H, --with-filename print the filename for each match\n\ 119953477Sobrien -h, --no-filename suppress the prefixing filename on output\n\ 1200131557Stjr --label=LABEL print LABEL as filename for standard input\n\ 1201131557Stjr -o, --only-matching show only the part of a line matching PATTERN\n\ 120253477Sobrien -q, --quiet, --silent suppress all normal output\n\ 120356233Sru --binary-files=TYPE assume that binary files are TYPE\n\ 1204131557Stjr TYPE is 'binary', 'text', or 'without-match'\n\ 120556920Sru -a, --text equivalent to --binary-files=text\n\ 120656920Sru -I equivalent to --binary-files=without-match\n\ 120753477Sobrien -d, --directories=ACTION how to handle directories\n\ 1208131557Stjr ACTION is 'read', 'recurse', or 'skip'\n\ 1209131557Stjr -D, --devices=ACTION how to handle devices, FIFOs and sockets\n\ 1210131557Stjr ACTION is 'read' or 'skip'\n\ 1211131557Stjr -R, -r, --recursive equivalent to --directories=recurse\n\ 1212131557Stjr --include=PATTERN files that match PATTERN will be examined\n\ 1213131557Stjr --exclude=PATTERN files that match PATTERN will be skipped.\n\ 1214131557Stjr --exclude-from=FILE files that match PATTERN in FILE will be skipped.\n\ 121553477Sobrien -L, --files-without-match only print FILE names containing no match\n\ 121653477Sobrien -l, --files-with-matches only print FILE names containing matches\n\ 121755379Sobrien -c, --count only print a count of matching lines per FILE\n\ 121855379Sobrien --null print 0 byte after FILE name\n")); 121953477Sobrien printf (_("\ 122053477Sobrien\n\ 122153477SobrienContext control:\n\ 122253477Sobrien -B, --before-context=NUM print NUM lines of leading context\n\ 122353477Sobrien -A, --after-context=NUM print NUM lines of trailing context\n\ 1224131557Stjr -C, --context=NUM print NUM lines of output context\n\ 122553477Sobrien -NUM same as --context=NUM\n\ 1226131557Stjr --color[=WHEN],\n\ 1227131557Stjr --colour[=WHEN] use markers to distinguish the matching string\n\ 1228131557Stjr WHEN may be `always', `never' or `auto'.\n\ 122953477Sobrien -U, --binary do not strip CR characters at EOL (MSDOS)\n\ 123053477Sobrien -u, --unix-byte-offsets report offsets as if CRs were not there (MSDOS)\n\ 123153477Sobrien\n\ 123255379Sobrien`egrep' means `grep -E'. `fgrep' means `grep -F'.\n\ 123355379SobrienWith no FILE, or when FILE is -, read standard input. If less than\n\ 123455379Sobrientwo FILEs given, assume -h. Exit status is 0 if match, 1 if no match,\n\ 123555379Sobrienand 2 if trouble.\n")); 123653477Sobrien printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n")); 123753477Sobrien } 123853477Sobrien exit (status); 123953451Speter} 124053451Speter 124155379Sobrien/* Set the matcher to M, reporting any conflicts. */ 124255379Sobrienstatic void 124356920Srusetmatcher (char const *m) 124455379Sobrien{ 124555379Sobrien if (matcher && strcmp (matcher, m) != 0) 1246131557Stjr error (2, 0, _("conflicting matchers specified")); 124755379Sobrien matcher = m; 124855379Sobrien} 124955379Sobrien 125053451Speter/* Go through the matchers vector and look for the specified matcher. 125153451Speter If we find it, install it in compile and execute, and return 1. */ 125253477Sobrienstatic int 125356920Sruinstall_matcher (char const *name) 125453451Speter{ 125553451Speter int i; 1256131557Stjr#if defined(HAVE_SETRLIMIT) 125753477Sobrien struct rlimit rlim; 125853477Sobrien#endif 125953451Speter 1260131557Stjr for (i = 0; matchers[i].compile; i++) 126153477Sobrien if (strcmp (name, matchers[i].name) == 0) 126253451Speter { 126353451Speter compile = matchers[i].compile; 126453451Speter execute = matchers[i].execute; 1265131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK) 126653477Sobrien /* I think every platform needs to do this, so that regex.c 126753477Sobrien doesn't oveflow the stack. The default value of 126853477Sobrien `re_max_failures' is too large for some platforms: it needs 126953477Sobrien more than 3MB-large stack. 127053477Sobrien 127153477Sobrien The test for HAVE_SETRLIMIT should go into `configure'. */ 127253477Sobrien if (!getrlimit (RLIMIT_STACK, &rlim)) 127353477Sobrien { 127453477Sobrien long newlim; 127553477Sobrien extern long int re_max_failures; /* from regex.c */ 127653477Sobrien 127753477Sobrien /* Approximate the amount regex.c needs, plus some more. */ 127853477Sobrien newlim = re_max_failures * 2 * 20 * sizeof (char *); 127953477Sobrien if (newlim > rlim.rlim_max) 128053477Sobrien { 128153477Sobrien newlim = rlim.rlim_max; 128253477Sobrien re_max_failures = newlim / (2 * 20 * sizeof (char *)); 128353477Sobrien } 128453477Sobrien if (rlim.rlim_cur < newlim) 1285131557Stjr { 1286131557Stjr rlim.rlim_cur = newlim; 1287131557Stjr setrlimit (RLIMIT_STACK, &rlim); 1288131557Stjr } 128953477Sobrien } 129053477Sobrien#endif 129153451Speter return 1; 129253451Speter } 129353451Speter return 0; 129453451Speter} 129553451Speter 129653705Sobrien/* Find the white-space-separated options specified by OPTIONS, and 129753705Sobrien using BUF to store copies of these options, set ARGV[0], ARGV[1], 129853705Sobrien etc. to the option copies. Return the number N of options found. 129953705Sobrien Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0] 130053705Sobrien etc. Backslash can be used to escape whitespace (and backslashes). */ 130153705Sobrienstatic int 130256920Sruprepend_args (char const *options, char *buf, char **argv) 130353705Sobrien{ 130453705Sobrien char const *o = options; 130553705Sobrien char *b = buf; 130653705Sobrien int n = 0; 130753705Sobrien 130853705Sobrien for (;;) 130953705Sobrien { 131053705Sobrien while (ISSPACE ((unsigned char) *o)) 131153705Sobrien o++; 131253705Sobrien if (!*o) 131353705Sobrien return n; 131453705Sobrien if (argv) 131553705Sobrien argv[n] = b; 131653705Sobrien n++; 131753705Sobrien 131853705Sobrien do 131953705Sobrien if ((*b++ = *o++) == '\\' && *o) 132053705Sobrien b[-1] = *o++; 132153705Sobrien while (*o && ! ISSPACE ((unsigned char) *o)); 132253705Sobrien 132353705Sobrien *b++ = '\0'; 132453705Sobrien } 132553705Sobrien} 132653705Sobrien 132753705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument 132853705Sobrien vector of a main program with argument count *PARGC and argument 132953705Sobrien vector *PARGV. */ 133053705Sobrienstatic void 133156920Sruprepend_default_options (char const *options, int *pargc, char ***pargv) 133253705Sobrien{ 133353705Sobrien if (options) 133453705Sobrien { 133553705Sobrien char *buf = xmalloc (strlen (options) + 1); 133653705Sobrien int prepended = prepend_args (options, buf, (char **) NULL); 133753705Sobrien int argc = *pargc; 133853705Sobrien char * const *argv = *pargv; 133953705Sobrien char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); 134053705Sobrien *pargc = prepended + argc; 134153705Sobrien *pargv = pp; 134253705Sobrien *pp++ = *argv++; 134353705Sobrien pp += prepend_args (options, buf, pp); 134453705Sobrien while ((*pp++ = *argv++)) 134553705Sobrien continue; 134653705Sobrien } 134753705Sobrien} 134853705Sobrien 1349131557Stjr/* Get the next non-digit option from ARGC and ARGV. 1350131557Stjr Return -1 if there are no more options. 1351131557Stjr Process any digit options that were encountered on the way, 1352131557Stjr and store the resulting integer into *DEFAULT_CONTEXT. */ 1353131557Stjrstatic int 1354131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context) 1355131557Stjr{ 1356131557Stjr int opt; 1357131557Stjr char buf[sizeof (uintmax_t) * CHAR_BIT + 4]; 1358131557Stjr char *p = buf; 1359131557Stjr 1360131557Stjr /* Set buf[0] to anything but '0', for the leading-zero test below. */ 1361131557Stjr buf[0] = '\0'; 1362131557Stjr 1363131557Stjr while (opt = getopt_long (argc, argv, short_options, long_options, NULL), 1364131557Stjr '0' <= opt && opt <= '9') 1365131557Stjr { 1366131557Stjr /* Suppress trivial leading zeros, to avoid incorrect 1367131557Stjr diagnostic on strings like 00000000000. */ 1368131557Stjr p -= buf[0] == '0'; 1369131557Stjr 1370131557Stjr *p++ = opt; 1371131557Stjr if (p == buf + sizeof buf - 4) 1372131557Stjr { 1373131557Stjr /* Too many digits. Append "..." to make context_length_arg 1374131557Stjr complain about "X...", where X contains the digits seen 1375131557Stjr so far. */ 1376131557Stjr strcpy (p, "..."); 1377131557Stjr p += 3; 1378131557Stjr break; 1379131557Stjr } 1380131557Stjr } 1381131557Stjr if (p != buf) 1382131557Stjr { 1383131557Stjr *p = '\0'; 1384131557Stjr context_length_arg (buf, default_context); 1385131557Stjr } 1386131557Stjr 1387131557Stjr return opt; 1388131557Stjr} 1389131557Stjr 139053451Speterint 139156920Srumain (int argc, char **argv) 139253451Speter{ 139353451Speter char *keys; 139453451Speter size_t keycc, oldcc, keyalloc; 139553477Sobrien int with_filenames; 139653477Sobrien int opt, cc, status; 139756920Sru int default_context; 139853451Speter FILE *fp; 139953451Speter extern char *optarg; 140053451Speter extern int optind; 140153477Sobrien 140253477Sobrien initialize_main (&argc, &argv); 1403131557Stjr program_name = argv[0]; 1404131557Stjr if (program_name && strrchr (program_name, '/')) 1405131557Stjr program_name = strrchr (program_name, '/') + 1; 140653477Sobrien 140753477Sobrien#if HAVE_LIBZ > 0 1408131557Stjr if (program_name[0] == 'z') { 140953477Sobrien Zflag = 1; 1410131557Stjr ++program_name; 141153477Sobrien } 141253451Speter#endif 1413131557Stjr if (program_name[0] == 'b') { 1414103372Sobrien BZflag = 1; 1415131557Stjr ++program_name; 1416103372Sobrien } 141753451Speter 141853477Sobrien#if defined(__MSDOS__) || defined(_WIN32) 141953477Sobrien /* DOS and MS-Windows use backslashes as directory separators, and usually 142053477Sobrien have an .exe suffix. They also have case-insensitive filesystems. */ 1421131557Stjr if (program_name) 142253477Sobrien { 1423131557Stjr char *p = program_name; 142453477Sobrien char *bslash = strrchr (argv[0], '\\'); 142553477Sobrien 1426131557Stjr if (bslash && bslash >= program_name) /* for mixed forward/backslash case */ 1427131557Stjr program_name = bslash + 1; 1428131557Stjr else if (program_name == argv[0] 142953477Sobrien && argv[0][0] && argv[0][1] == ':') /* "c:progname" */ 1430131557Stjr program_name = argv[0] + 2; 143153477Sobrien 143253477Sobrien /* Collapse the letter-case, so `strcmp' could be used hence. */ 143353477Sobrien for ( ; *p; p++) 143453477Sobrien if (*p >= 'A' && *p <= 'Z') 143553477Sobrien *p += 'a' - 'A'; 143653477Sobrien 143753477Sobrien /* Remove the .exe extension, if any. */ 1438131557Stjr if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0) 143953477Sobrien *p = '\0'; 144053477Sobrien } 144153451Speter#endif 144253451Speter 144353451Speter keys = NULL; 144453451Speter keycc = 0; 144553477Sobrien with_filenames = 0; 144655379Sobrien eolbyte = '\n'; 144755379Sobrien filename_mask = ~0; 144853477Sobrien 1449131557Stjr max_count = TYPE_MAXIMUM (off_t); 1450131557Stjr 145153477Sobrien /* The value -1 means to use DEFAULT_CONTEXT. */ 145253477Sobrien out_after = out_before = -1; 145353477Sobrien /* Default before/after context: chaged by -C/-NUM options */ 145453477Sobrien default_context = 0; 1455131557Stjr /* Changed by -o option */ 1456131557Stjr only_matching = 0; 145753477Sobrien 1458131557Stjr /* Internationalization. */ 1459131557Stjr#if defined(HAVE_SETLOCALE) 146053477Sobrien setlocale (LC_ALL, ""); 146153451Speter#endif 1462131557Stjr#if defined(ENABLE_NLS) 146353477Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 146453477Sobrien textdomain (PACKAGE); 146553451Speter#endif 146653451Speter 1467131557Stjr atexit (close_stdout); 1468131557Stjr 146953705Sobrien prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv); 147053705Sobrien 1471131557Stjr while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1) 147253451Speter switch (opt) 147353451Speter { 147453451Speter case 'A': 1475131557Stjr context_length_arg (optarg, &out_after); 147653451Speter break; 1477131557Stjr 147853451Speter case 'B': 1479131557Stjr context_length_arg (optarg, &out_before); 148053451Speter break; 1481131557Stjr 148253451Speter case 'C': 148353477Sobrien /* Set output match context, but let any explicit leading or 148453477Sobrien trailing amount specified with -A or -B stand. */ 1485131557Stjr context_length_arg (optarg, &default_context); 1486131557Stjr break; 1487131557Stjr 1488131557Stjr case 'D': 1489131557Stjr if (strcmp (optarg, "read") == 0) 1490131557Stjr devices = READ_DEVICES; 1491131557Stjr else if (strcmp (optarg, "skip") == 0) 1492131557Stjr devices = SKIP_DEVICES; 149353477Sobrien else 1494131557Stjr error (2, 0, _("unknown devices method")); 149553451Speter break; 1496131557Stjr 149753451Speter case 'E': 149855379Sobrien setmatcher ("egrep"); 149953451Speter break; 1500131557Stjr 150153451Speter case 'F': 150255379Sobrien setmatcher ("fgrep"); 150353451Speter break; 1504131557Stjr 1505131557Stjr case 'P': 1506131557Stjr setmatcher ("perl"); 1507131557Stjr break; 1508131557Stjr 150953451Speter case 'G': 151055379Sobrien setmatcher ("grep"); 151153451Speter break; 1512131557Stjr 151353477Sobrien case 'H': 151453477Sobrien with_filenames = 1; 151553477Sobrien break; 1516131557Stjr 151756920Sru case 'I': 151856920Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 151956920Sru break; 1520103372Sobrien case 'J': 1521104555Sobrien if (Zflag) 1522104555Sobrien { 1523104555Sobrien printf (_("Cannot mix -Z and -J.\n")); 1524104555Sobrien usage (2); 1525104555Sobrien } 1526103372Sobrien BZflag = 1; 1527103372Sobrien break; 1528131557Stjr 152955379Sobrien case 'U': 1530131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 153153477Sobrien dos_use_file_type = DOS_BINARY; 153255379Sobrien#endif 153353477Sobrien break; 1534131557Stjr 153553477Sobrien case 'u': 1536131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS) 153753477Sobrien dos_report_unix_offset = 1; 153855379Sobrien#endif 153953477Sobrien break; 1540131557Stjr 154153451Speter case 'V': 154253477Sobrien show_version = 1; 154353451Speter break; 1544131557Stjr 154553451Speter case 'X': 154655379Sobrien setmatcher (optarg); 154753451Speter break; 1548131557Stjr 154953451Speter case 'a': 155056233Sru binary_files = TEXT_BINARY_FILES; 155153451Speter break; 1552131557Stjr 155353451Speter case 'b': 155453451Speter out_byte = 1; 155553451Speter break; 1556131557Stjr 155753451Speter case 'c': 155853451Speter count_matches = 1; 155953451Speter break; 1560131557Stjr 156153477Sobrien case 'd': 156253477Sobrien if (strcmp (optarg, "read") == 0) 156353477Sobrien directories = READ_DIRECTORIES; 156453477Sobrien else if (strcmp (optarg, "skip") == 0) 156553477Sobrien directories = SKIP_DIRECTORIES; 156653477Sobrien else if (strcmp (optarg, "recurse") == 0) 156753477Sobrien directories = RECURSE_DIRECTORIES; 156853477Sobrien else 1569131557Stjr error (2, 0, _("unknown directories method")); 157053477Sobrien break; 1571131557Stjr 157253451Speter case 'e': 157353477Sobrien cc = strlen (optarg); 157453477Sobrien keys = xrealloc (keys, keycc + cc + 1); 157553477Sobrien strcpy (&keys[keycc], optarg); 157653451Speter keycc += cc; 157753477Sobrien keys[keycc++] = '\n'; 157853451Speter break; 1579131557Stjr 158053451Speter case 'f': 158153477Sobrien fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin; 158253451Speter if (!fp) 1583131557Stjr error (2, errno, "%s", optarg); 158453477Sobrien for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2) 158553451Speter ; 158653477Sobrien keys = xrealloc (keys, keyalloc); 158753451Speter oldcc = keycc; 158853477Sobrien while (!feof (fp) 158953477Sobrien && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0) 159053451Speter { 159153451Speter keycc += cc; 159253477Sobrien if (keycc == keyalloc - 1) 159353477Sobrien keys = xrealloc (keys, keyalloc *= 2); 159453451Speter } 159553451Speter if (fp != stdin) 159653451Speter fclose(fp); 159753477Sobrien /* Append final newline if file ended in non-newline. */ 159853477Sobrien if (oldcc != keycc && keys[keycc - 1] != '\n') 159953477Sobrien keys[keycc++] = '\n'; 160053451Speter break; 1601131557Stjr 160253451Speter case 'h': 160353451Speter no_filenames = 1; 160453451Speter break; 1605131557Stjr 160653451Speter case 'i': 160753451Speter case 'y': /* For old-timers . . . */ 160853451Speter match_icase = 1; 160953451Speter break; 1610131557Stjr 161153451Speter case 'L': 161253451Speter /* Like -l, except list files that don't contain matches. 161353451Speter Inspired by the same option in Hume's gre. */ 161453451Speter list_files = -1; 161553451Speter break; 1616131557Stjr 161753451Speter case 'l': 161853451Speter list_files = 1; 161953451Speter break; 1620131557Stjr 1621131557Stjr case 'm': 1622131557Stjr { 1623131557Stjr uintmax_t value; 1624131557Stjr switch (xstrtoumax (optarg, 0, 10, &value, "")) 1625131557Stjr { 1626131557Stjr case LONGINT_OK: 1627131557Stjr max_count = value; 1628131557Stjr if (0 <= max_count && max_count == value) 1629131557Stjr break; 1630131557Stjr /* Fall through. */ 1631131557Stjr case LONGINT_OVERFLOW: 1632131557Stjr max_count = TYPE_MAXIMUM (off_t); 1633131557Stjr break; 1634131557Stjr 1635131557Stjr default: 1636131557Stjr error (2, 0, _("invalid max count")); 1637131557Stjr } 1638131557Stjr } 1639131557Stjr break; 1640131557Stjr 164153451Speter case 'n': 164253451Speter out_line = 1; 164353451Speter break; 1644131557Stjr 1645131557Stjr case 'o': 1646131557Stjr only_matching = 1; 1647131557Stjr break; 1648131557Stjr 164953451Speter case 'q': 1650131557Stjr exit_on_match = 1; 1651131557Stjr close_stdout_set_status(0); 165253451Speter break; 1653131557Stjr 165453478Sobrien case 'R': 165553477Sobrien case 'r': 165653477Sobrien directories = RECURSE_DIRECTORIES; 165753477Sobrien break; 1658131557Stjr 165953451Speter case 's': 166053451Speter suppress_errors = 1; 166153451Speter break; 1662131557Stjr 166353451Speter case 'v': 166453451Speter out_invert = 1; 166553451Speter break; 1666131557Stjr 166753451Speter case 'w': 166853451Speter match_words = 1; 166953451Speter break; 1670131557Stjr 167153451Speter case 'x': 167253451Speter match_lines = 1; 167353451Speter break; 1674131557Stjr 167555379Sobrien case 'Z': 167655379Sobrien#if HAVE_LIBZ > 0 1677104555Sobrien if (BZflag) 1678104555Sobrien { 1679104555Sobrien printf (_("Cannot mix -J and -Z.\n")); 1680104555Sobrien usage (2); 1681104555Sobrien } 168255379Sobrien Zflag = 1; 168355379Sobrien#else 168455379Sobrien filename_mask = 0; 168555379Sobrien#endif 168655379Sobrien break; 1687131557Stjr 168855379Sobrien case 'z': 168955379Sobrien eolbyte = '\0'; 169055379Sobrien break; 1691131557Stjr 169256233Sru case BINARY_FILES_OPTION: 169356233Sru if (strcmp (optarg, "binary") == 0) 169456233Sru binary_files = BINARY_BINARY_FILES; 169556233Sru else if (strcmp (optarg, "text") == 0) 169656233Sru binary_files = TEXT_BINARY_FILES; 169756233Sru else if (strcmp (optarg, "without-match") == 0) 169856233Sru binary_files = WITHOUT_MATCH_BINARY_FILES; 169956233Sru else 1700131557Stjr error (2, 0, _("unknown binary-files type")); 170156233Sru break; 1702131557Stjr 1703131557Stjr case COLOR_OPTION: 1704131557Stjr if(optarg) { 1705131557Stjr if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") || 1706131557Stjr !strcasecmp(optarg, "force")) 1707131557Stjr color_option = 1; 1708131557Stjr else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") || 1709131557Stjr !strcasecmp(optarg, "none")) 1710131557Stjr color_option = 0; 1711131557Stjr else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") || 1712131557Stjr !strcasecmp(optarg, "if-tty")) 1713131557Stjr color_option = 2; 1714131557Stjr else 1715131557Stjr show_help = 1; 1716131557Stjr } else 1717131557Stjr color_option = 2; 1718131557Stjr if(color_option == 2) { 1719131557Stjr if(isatty(STDOUT_FILENO) && getenv("TERM") && 1720131557Stjr strcmp(getenv("TERM"), "dumb")) 1721131557Stjr color_option = 1; 1722131557Stjr else 1723131557Stjr color_option = 0; 1724131557Stjr } 1725131557Stjr break; 1726131557Stjr 1727131557Stjr case EXCLUDE_OPTION: 1728131557Stjr if (!excluded_patterns) 1729131557Stjr excluded_patterns = new_exclude (); 1730131557Stjr add_exclude (excluded_patterns, optarg); 1731131557Stjr break; 1732131557Stjr 1733131557Stjr case EXCLUDE_FROM_OPTION: 1734131557Stjr if (!excluded_patterns) 1735131557Stjr excluded_patterns = new_exclude (); 1736131557Stjr if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n') 1737131557Stjr != 0) 1738131557Stjr { 1739131557Stjr error (2, errno, "%s", optarg); 1740131557Stjr } 1741131557Stjr break; 1742131557Stjr 1743131557Stjr case INCLUDE_OPTION: 1744131557Stjr if (!included_patterns) 1745131557Stjr included_patterns = new_exclude (); 1746131557Stjr add_exclude (included_patterns, optarg); 1747131557Stjr break; 1748131557Stjr 1749131557Stjr case LINE_BUFFERED_OPTION: 1750131557Stjr line_buffered = 1; 1751131557Stjr break; 1752131557Stjr 1753131557Stjr case LABEL_OPTION: 1754131557Stjr label = optarg; 1755131557Stjr break; 1756131557Stjr 175753477Sobrien case 0: 175853477Sobrien /* long options */ 175953477Sobrien break; 1760131557Stjr 176153451Speter default: 176253477Sobrien usage (2); 176353451Speter break; 1764131557Stjr 176553451Speter } 176653451Speter 1767131557Stjr /* POSIX.2 says that -q overrides -l, which in turn overrides the 1768131557Stjr other output options. */ 1769131557Stjr if (exit_on_match) 1770131557Stjr list_files = 0; 1771131557Stjr if (exit_on_match | list_files) 1772131557Stjr { 1773131557Stjr count_matches = 0; 1774131557Stjr done_on_match = 1; 1775131557Stjr } 1776131557Stjr out_quiet = count_matches | done_on_match; 1777131557Stjr 177853477Sobrien if (out_after < 0) 177953477Sobrien out_after = default_context; 178053477Sobrien if (out_before < 0) 178153477Sobrien out_before = default_context; 178253477Sobrien 1783131557Stjr if (color_option) 1784131557Stjr { 1785131557Stjr char *userval = getenv ("GREP_COLOR"); 1786131557Stjr if (userval != NULL && *userval != '\0') 1787131557Stjr grep_color = userval; 1788131557Stjr } 1789131557Stjr 179055379Sobrien if (! matcher) 1791131557Stjr matcher = program_name; 179255379Sobrien 179353477Sobrien if (show_version) 179453477Sobrien { 179555379Sobrien printf (_("%s (GNU grep) %s\n"), matcher, VERSION); 179653477Sobrien printf ("\n"); 179753477Sobrien printf (_("\ 1798131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n")); 179953477Sobrien printf (_("\ 180053477SobrienThis is free software; see the source for copying conditions. There is NO\n\ 180153477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")); 180253477Sobrien printf ("\n"); 180353477Sobrien exit (0); 180453477Sobrien } 180553477Sobrien 180653477Sobrien if (show_help) 180753477Sobrien usage (0); 180853477Sobrien 180953477Sobrien if (keys) 181053477Sobrien { 181153477Sobrien if (keycc == 0) 1812131557Stjr { 1813131557Stjr /* No keys were specified (e.g. -f /dev/null). Match nothing. */ 1814131557Stjr out_invert ^= 1; 1815131557Stjr match_lines = match_words = 0; 1816131557Stjr } 181753477Sobrien else 181853477Sobrien /* Strip trailing newline. */ 181953477Sobrien --keycc; 182053477Sobrien } 182153477Sobrien else 182253451Speter if (optind < argc) 182353451Speter { 182453451Speter keys = argv[optind++]; 182553477Sobrien keycc = strlen (keys); 182653451Speter } 182753451Speter else 182853477Sobrien usage (2); 182953451Speter 183055379Sobrien if (!install_matcher (matcher) && !install_matcher ("default")) 183153477Sobrien abort (); 183253451Speter 1833131564Stjr#ifdef MBS_SUPPORT 1834131564Stjr if (MB_CUR_MAX != 1 && match_icase) 1835131564Stjr { 1836131564Stjr wchar_t wc; 1837131564Stjr mbstate_t cur_state, prev_state; 1838131564Stjr int i, len = strlen(keys); 1839131564Stjr 1840131564Stjr memset(&cur_state, 0, sizeof(mbstate_t)); 1841131564Stjr for (i = 0; i <= len ;) 1842131564Stjr { 1843131564Stjr size_t mbclen; 1844131564Stjr mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state); 1845131564Stjr if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0) 1846131564Stjr { 1847131564Stjr /* An invalid sequence, or a truncated multibyte character. 1848131564Stjr We treat it as a singlebyte character. */ 1849131564Stjr mbclen = 1; 1850131564Stjr } 1851131564Stjr else 1852131564Stjr { 1853131564Stjr if (iswupper((wint_t)wc)) 1854131564Stjr { 1855131564Stjr wc = towlower((wint_t)wc); 1856131564Stjr wcrtomb(keys + i, wc, &cur_state); 1857131564Stjr } 1858131564Stjr } 1859131564Stjr i += mbclen; 1860131564Stjr } 1861131564Stjr } 1862131564Stjr#endif /* MBS_SUPPORT */ 1863131564Stjr 186453451Speter (*compile)(keys, keycc); 186553451Speter 186653477Sobrien if ((argc - optind > 1 && !no_filenames) || with_filenames) 186753451Speter out_file = 1; 186853451Speter 1869131557Stjr#ifdef SET_BINARY 187053477Sobrien /* Output is set to binary mode because we shouldn't convert 187153477Sobrien NL to CR-LF pairs, especially when grepping binary files. */ 187253477Sobrien if (!isatty (1)) 187353477Sobrien SET_BINARY (1); 187453451Speter#endif 187553451Speter 1876131557Stjr if (max_count == 0) 1877131557Stjr exit (1); 187853451Speter 187953451Speter if (optind < argc) 188053451Speter { 188153477Sobrien status = 1; 188253477Sobrien do 188353451Speter { 188453477Sobrien char *file = argv[optind]; 1885131557Stjr if ((included_patterns || excluded_patterns) 1886131557Stjr && !isdir (file)) 1887131557Stjr { 1888131557Stjr if (included_patterns && 1889131557Stjr ! excluded_filename (included_patterns, file, 0)) 1890131557Stjr continue; 1891131557Stjr if (excluded_patterns && 1892131557Stjr excluded_filename (excluded_patterns, file, 0)) 1893131557Stjr continue; 1894131557Stjr } 189553477Sobrien status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file, 189653477Sobrien &stats_base); 189753451Speter } 189853477Sobrien while ( ++optind < argc); 189953451Speter } 190053477Sobrien else 190153477Sobrien status = grepfile ((char *) NULL, &stats_base); 190253451Speter 1903131557Stjr /* We register via atexit() to test stdout. */ 190453477Sobrien exit (errseen ? 2 : status); 190553451Speter} 1906131557Stjr/* vim:set shiftwidth=2: */ 1907