⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 grep.c

📁 linux平台中
💻 C
📖 第 1 页 / 共 4 页
字号:
/* grep.c - main driver file for grep.   Copyright 1992, 1997-1999, 2000 Free Software Foundation, Inc.   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2, or (at your option)   any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA   02111-1307, USA.  *//* Written July 1992 by Mike Haertel.  */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <sys/types.h>#include <sys/stat.h>#if defined(HAVE_MMAP)# include <sys/mman.h>#endif#if defined(HAVE_SETRLIMIT)# include <sys/time.h># include <sys/resource.h>#endif#include <stdio.h>#include "system.h"#include "getopt.h"#include "getpagesize.h"#include "grep.h"#include "savedir.h"#include "xstrtol.h"#include "xalloc.h"#include "error.h"#include "exclude.h"#include "closeout.h"#undef MAX#define MAX(A,B) ((A) > (B) ? (A) : (B))struct stats{  struct stats const *parent;  struct stat stat;};/* base of chain of stat buffers, used to detect directory loops */static struct stats stats_base;/* if non-zero, display usage information and exit */static int show_help;/* If non-zero, print the version on standard output and exit.  */static int show_version;/* If nonzero, suppress diagnostics for nonexistent or unreadable files.  */static int suppress_errors;/* If nonzero, use mmap if possible.  */static int mmap_option;/* If nonzero, use grep_color marker.  */static int color_option;/* If nonzero, show only the part of a line matching the expression. */static int only_matching;/* The color string used.  The user can overwrite it using the environment   variable GREP_COLOR.  The default is to print red.  */static const char *grep_color = "01;31";static struct exclude *excluded_patterns;static struct exclude *included_patterns;/* Short options.  */static char const short_options[] ="0123456789A:B:C:D:EFGHIPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz";/* Non-boolean long options that have no corresponding short equivalents.  */enum{  BINARY_FILES_OPTION = CHAR_MAX + 1,  COLOR_OPTION,  INCLUDE_OPTION,  EXCLUDE_OPTION,  EXCLUDE_FROM_OPTION,  LINE_BUFFERED_OPTION,  LABEL_OPTION};/* Long options equivalences. */static struct option const long_options[] ={  {"after-context", required_argument, NULL, 'A'},  {"basic-regexp", no_argument, NULL, 'G'},  {"before-context", required_argument, NULL, 'B'},  {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},  {"byte-offset", no_argument, NULL, 'b'},  {"context", required_argument, NULL, 'C'},  {"color", optional_argument, NULL, COLOR_OPTION},  {"colour", optional_argument, NULL, COLOR_OPTION},  {"count", no_argument, NULL, 'c'},  {"devices", required_argument, NULL, 'D'},  {"directories", required_argument, NULL, 'd'},  {"extended-regexp", no_argument, NULL, 'E'},  {"exclude", required_argument, NULL, EXCLUDE_OPTION},  {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION},  {"file", required_argument, NULL, 'f'},  {"files-with-matches", no_argument, NULL, 'l'},  {"files-without-match", no_argument, NULL, 'L'},  {"fixed-regexp", no_argument, NULL, 'F'},  {"fixed-strings", no_argument, NULL, 'F'},  {"help", no_argument, &show_help, 1},  {"include", required_argument, NULL, INCLUDE_OPTION},  {"ignore-case", no_argument, NULL, 'i'},  {"label", required_argument, NULL, LABEL_OPTION},  {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION},  {"line-number", no_argument, NULL, 'n'},  {"line-regexp", no_argument, NULL, 'x'},  {"max-count", required_argument, NULL, 'm'},  {"mmap", no_argument, &mmap_option, 1},  {"no-filename", no_argument, NULL, 'h'},  {"no-messages", no_argument, NULL, 's'},  {"null", no_argument, NULL, 'Z'},  {"null-data", no_argument, NULL, 'z'},  {"only-matching", no_argument, NULL, 'o'},  {"perl-regexp", no_argument, NULL, 'P'},  {"quiet", no_argument, NULL, 'q'},  {"recursive", no_argument, NULL, 'r'},  {"recursive", no_argument, NULL, 'R'},  {"regexp", required_argument, NULL, 'e'},  {"invert-match", no_argument, NULL, 'v'},  {"silent", no_argument, NULL, 'q'},  {"text", no_argument, NULL, 'a'},  {"binary", no_argument, NULL, 'U'},  {"unix-byte-offsets", no_argument, NULL, 'u'},  {"version", no_argument, NULL, 'V'},  {"with-filename", no_argument, NULL, 'H'},  {"word-regexp", no_argument, NULL, 'w'},  {0, 0, 0, 0}};/* Define flags declared in grep.h. */int match_icase;int match_words;int match_lines;unsigned char eolbyte;/* For error messages. *//* The name the program was run with, stripped of any leading path. */char *program_name;static char const *filename;static int errseen;/* How to handle directories.  */static enum  {    READ_DIRECTORIES,    RECURSE_DIRECTORIES,    SKIP_DIRECTORIES  } directories = READ_DIRECTORIES;/* How to handle devices. */static enum  {    READ_DEVICES,    SKIP_DEVICES  } devices = READ_DEVICES;static int grepdir PARAMS ((char const *, struct stats const *));#if defined(HAVE_DOS_FILE_CONTENTS)static inline int undossify_input PARAMS ((register char *, size_t));#endif/* Functions we'll use to search. */static void (*compile) PARAMS ((char const *, size_t));static size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));/* Like error, but suppress the diagnostic if requested.  */static voidsuppressible_error (char const *mesg, int errnum){  if (! suppress_errors)    error (0, errnum, "%s", mesg);  errseen = 1;}/* Convert STR to a positive integer, storing the result in *OUT.   STR must be a valid context length argument; report an error if it   isn't.  */static voidcontext_length_arg (char const *str, int *out){  uintmax_t value;  if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK	 && 0 <= (*out = value)	 && *out == value))    {      error (2, 0, "%s: %s\n", str, _("invalid context length argument"));    }}/* Hairy buffering mechanism for grep.  The intent is to keep   all reads aligned on a page boundary and multiples of the   page size, unless a read yields a partial page.  */static char *buffer;		/* Base of buffer. */static size_t bufalloc;		/* Allocated buffer size, counting slop. */#define INITIAL_BUFSIZE 32768	/* Initial buffer size, not counting slop. */static int bufdesc;		/* File descriptor. */static char *bufbeg;		/* Beginning of user-visible stuff. */static char *buflim;		/* Limit of user-visible stuff. */static size_t pagesize;		/* alignment of memory pages */static off_t bufoffset;		/* Read offset; defined on regular files.  */static off_t after_last_match;	/* Pointer after last matching line that				   would have been output if we were				   outputting characters. */#if defined(HAVE_MMAP)static int bufmapped;		/* True if buffer is memory-mapped.  */static off_t initial_bufoffset;	/* Initial value of bufoffset. */#else# define bufmapped 0#endif/* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be   an integer or a pointer.  Both args must be free of side effects.  */#define ALIGN_TO(val, alignment) \  ((size_t) (val) % (alignment) == 0 \   ? (val) \   : (val) + ((alignment) - (size_t) (val) % (alignment)))/* Reset the buffer for a new file, returning zero if we should skip it.   Initialize on the first time through. */static intreset (int fd, char const *file, struct stats *stats){  if (! pagesize)    {      pagesize = getpagesize ();      if (pagesize == 0 || 2 * pagesize + 1 <= pagesize)	abort ();      bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1;      buffer = xmalloc (bufalloc);    }  bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);  bufbeg[-1] = eolbyte;  bufdesc = fd;  if (fstat (fd, &stats->stat) != 0)    {      error (0, errno, "fstat");      return 0;    }  if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))    return 0;#ifndef DJGPP  if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode)))#else  if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode)))#endif    return 0;  if (S_ISREG (stats->stat.st_mode))    {      if (file)	bufoffset = 0;      else	{	  bufoffset = lseek (fd, 0, SEEK_CUR);	  if (bufoffset < 0)	    {	      error (0, errno, "lseek");	      return 0;	    }	}#if defined(HAVE_MMAP)      initial_bufoffset = bufoffset;      bufmapped = mmap_option && bufoffset % pagesize == 0;#endif    }  else    {#if defined(HAVE_MMAP)      bufmapped = 0;#endif    }  return 1;}/* Read new stuff into the buffer, saving the specified   amount of old stuff.  When we're done, 'bufbeg' points   to the beginning of the buffer contents, and 'buflim'   points just after the end.  Return zero if there's an error.  */static intfillbuf (size_t save, struct stats const *stats){  size_t fillsize = 0;  int cc = 1;  char *readbuf;  size_t readsize;  /* Offset from start of buffer to start of old stuff     that we want to save.  */  size_t saved_offset = buflim - save - buffer;  if (pagesize <= buffer + bufalloc - buflim)    {      readbuf = buflim;      bufbeg = buflim - save;    }  else    {      size_t minsize = save + pagesize;      size_t newsize;      size_t newalloc;      char *newbuf;      /* Grow newsize until it is at least as great as minsize.  */      for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)	  xalloc_die ();      /* Try not to allocate more memory than the file size indicates,	 as that might cause unnecessary memory exhaustion if the file	 is large.  However, do not use the original file size as a	 heuristic if we've already read past the file end, as most	 likely the file is growing.  */      if (S_ISREG (stats->stat.st_mode))	{	  off_t to_be_read = stats->stat.st_size - bufoffset;	  off_t maxsize_off = save + to_be_read;	  if (0 <= to_be_read && to_be_read <= maxsize_off	      && maxsize_off == (size_t) maxsize_off	      && minsize <= (size_t) maxsize_off	      && (size_t) maxsize_off < newsize)	    newsize = maxsize_off;	}      /* Add enough room so that the buffer is aligned and has room	 for byte sentinels fore and aft.  */      newalloc = newsize + pagesize + 1;      newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;      readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);      bufbeg = readbuf - save;      memmove (bufbeg, buffer + saved_offset, save);      bufbeg[-1] = eolbyte;      if (newbuf != buffer)	{	  free (buffer);	  buffer = newbuf;	}    }  readsize = buffer + bufalloc - readbuf;  readsize -= readsize % pagesize;#if defined(HAVE_MMAP)  if (bufmapped)    {      size_t mmapsize = readsize;      /* Don't mmap past the end of the file; some hosts don't allow this.	 Use `read' on the last page.  */      if (stats->stat.st_size - bufoffset < mmapsize)	{	  mmapsize = stats->stat.st_size - bufoffset;	  mmapsize -= mmapsize % pagesize;	}      if (mmapsize	  && (mmap ((caddr_t) readbuf, mmapsize,		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,		    bufdesc, bufoffset)	      != (caddr_t) -1))	{	  /* Do not bother to use madvise with MADV_SEQUENTIAL or	     MADV_WILLNEED on the mmapped memory.  One might think it	     would help, but it slows us down about 30% on SunOS 4.1.  */	  fillsize = mmapsize;	}      else	{	  /* Stop using mmap on this file.  Synchronize the file	     offset.  Do not warn about mmap failures.  On some hosts	     (e.g. Solaris 2.5) mmap can fail merely because some	     other process has an advisory read lock on the file.	     There's no point alarming the user about this misfeature.  */	  bufmapped = 0;	  if (bufoffset != initial_bufoffset	      && lseek (bufdesc, bufoffset, SEEK_SET) < 0)	    {	      error (0, errno, "lseek");	      cc = 0;	    }	}    }#endif /*HAVE_MMAP*/  if (! fillsize)    {      ssize_t bytesread;      while ((bytesread = read (bufdesc, readbuf, readsize)) < 0	     && errno == EINTR)	continue;      if (bytesread < 0)	cc = 0;      else	fillsize = bytesread;    }  bufoffset += fillsize;#if defined(HAVE_DOS_FILE_CONTENTS)  if (fillsize)    fillsize = undossify_input (readbuf, fillsize);#endif  buflim = readbuf + fillsize;  return cc;}/* Flags controlling the style of output. */static enum{  BINARY_BINARY_FILES,  TEXT_BINARY_FILES,  WITHOUT_MATCH_BINARY_FILES} binary_files;		/* How to handle binary files.  */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -