📄 pcregrep.c
字号:
/************************************************** pcregrep program **************************************************//* This is a grep program that uses the PCRE regular expression library to doits pattern matching. On a Unix or Win32 system it can recurse intodirectories. Copyright (c) 1997-2006 University of Cambridge-----------------------------------------------------------------------------Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BELIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ORCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OFSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESSINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.-----------------------------------------------------------------------------*/#include <ctype.h>#include <locale.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include "config.h"#include "pcre.h"#define FALSE 0#define TRUE 1typedef int BOOL;#define VERSION "4.2 09-Jan-2006"#define MAX_PATTERN_COUNT 100#if BUFSIZ > 8192#define MBUFTHIRD BUFSIZ#else#define MBUFTHIRD 8192#endif/* Values for the "filenames" variable, which specifies options for file nameoutput. The order is important; it is assumed that a file name is wanted forall values greater than FN_DEFAULT. */enum { FN_NONE, FN_DEFAULT, FN_ONLY, FN_NOMATCH_ONLY, FN_FORCE };/* Actions for the -d and -D options */enum { dee_READ, dee_SKIP, dee_RECURSE };enum { DEE_READ, DEE_SKIP };/* Actions for special processing options (flag bits) */#define PO_WORD_MATCH 0x0001#define PO_LINE_MATCH 0x0002#define PO_FIXED_STRINGS 0x0004/************************************************** Global variables **************************************************//* Jeffrey Friedl has some debugging requirements that are not part of theregular code. */#ifdef JFRIEDL_DEBUGstatic int S_arg = -1;static unsigned int jfriedl_XR = 0; /* repeat regex attempt this many times */static unsigned int jfriedl_XT = 0; /* replicate text this many times */static const char *jfriedl_prefix = "";static const char *jfriedl_postfix = "";#endifstatic char *colour_string = (char *)"1;31";static char *colour_option = NULL;static char *dee_option = NULL;static char *DEE_option = NULL;static char *pattern_filename = NULL;static char *stdin_name = (char *)"(standard input)";static char *locale = NULL;static const unsigned char *pcretables = NULL;static int pattern_count = 0;static pcre **pattern_list;static pcre_extra **hints_list;static char *include_pattern = NULL;static char *exclude_pattern = NULL;static pcre *include_compiled = NULL;static pcre *exclude_compiled = NULL;static int after_context = 0;static int before_context = 0;static int both_context = 0;static int dee_action = dee_READ;static int DEE_action = DEE_READ;static int error_count = 0;static int filenames = FN_DEFAULT;static int process_options = 0;static BOOL count_only = FALSE;static BOOL do_colour = FALSE;static BOOL hyphenpending = FALSE;static BOOL invert = FALSE;static BOOL multiline = FALSE;static BOOL number = FALSE;static BOOL only_matching = FALSE;static BOOL quiet = FALSE;static BOOL silent = FALSE;/* Structure for options and list of them */enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_OP_NUMBER, OP_PATLIST };typedef struct option_item { int type; int one_char; void *dataptr; const char *long_name; const char *help_text;} option_item;/* Options without a single-letter equivalent get a negative value. This can beused to identify them. */#define N_COLOUR (-1)#define N_EXCLUDE (-2)#define N_HELP (-3)#define N_INCLUDE (-4)#define N_LABEL (-5)#define N_LOCALE (-6)#define N_NULL (-7)static option_item optionlist[] = { { OP_NODATA, N_NULL, NULL, "", " terminate options" }, { OP_NODATA, N_HELP, NULL, "help", "display this help and exit" }, { OP_NUMBER, 'A', &after_context, "after-context=number", "set number of following context lines" }, { OP_NUMBER, 'B', &before_context, "before-context=number", "set number of prior context lines" }, { OP_OP_STRING, N_COLOUR, &colour_option, "color=option", "matched text color option" }, { OP_NUMBER, 'C', &both_context, "context=number", "set number of context lines, before & after" }, { OP_NODATA, 'c', NULL, "count", "print only a count of matching lines per FILE" }, { OP_OP_STRING, N_COLOUR, &colour_option, "colour=option", "matched text colour option" }, { OP_STRING, 'D', &DEE_option, "devices=action","how to handle devices, FIFOs, and sockets" }, { OP_STRING, 'd', &dee_option, "directories=action", "how to handle directories" }, { OP_PATLIST, 'e', NULL, "regex(p)", "specify pattern (may be used more than once)" }, { OP_NODATA, 'F', NULL, "fixed_strings", "patterns are sets of newline-separated strings" }, { OP_STRING, 'f', &pattern_filename, "file=path", "read patterns from file" }, { OP_NODATA, 'H', NULL, "with-filename", "force the prefixing filename on output" }, { OP_NODATA, 'h', NULL, "no-filename", "suppress the prefixing filename on output" }, { OP_NODATA, 'i', NULL, "ignore-case", "ignore case distinctions" }, { OP_NODATA, 'l', NULL, "files-with-matches", "print only FILE names containing matches" }, { OP_NODATA, 'L', NULL, "files-without-match","print only FILE names not containing matches" }, { OP_STRING, N_LABEL, &stdin_name, "label=name", "set name for standard input" }, { OP_STRING, N_LOCALE, &locale, "locale=locale", "use the named locale" }, { OP_NODATA, 'M', NULL, "multiline", "run in multiline mode" }, { OP_NODATA, 'n', NULL, "line-number", "print line number with output lines" }, { OP_NODATA, 'o', NULL, "only-matching", "show only the part of the line that matched" }, { OP_NODATA, 'q', NULL, "quiet", "suppress output, just set return code" }, { OP_NODATA, 'r', NULL, "recursive", "recursively scan sub-directories" }, { OP_STRING, N_EXCLUDE,&exclude_pattern, "exclude=pattern","exclude matching files when recursing" }, { OP_STRING, N_INCLUDE,&include_pattern, "include=pattern","include matching files when recursing" },#ifdef JFRIEDL_DEBUG { OP_OP_NUMBER, 'S', &S_arg, "jeffS", "replace matched (sub)string with X" },#endif { OP_NODATA, 's', NULL, "no-messages", "suppress error messages" }, { OP_NODATA, 'u', NULL, "utf-8", "use UTF-8 mode" }, { OP_NODATA, 'V', NULL, "version", "print version information and exit" }, { OP_NODATA, 'v', NULL, "invert-match", "select non-matching lines" }, { OP_NODATA, 'w', NULL, "word-regex(p)", "force patterns to match only as words" }, { OP_NODATA, 'x', NULL, "line-regex(p)", "force patterns to match only whole lines" }, { OP_NODATA, 0, NULL, NULL, NULL }};/* Tables for prefixing and suffixing patterns, according to the -w, -x, and -Foptions. These set the 1, 2, and 4 bits in process_options, respectively. Notethat the combination of -w and -x has the same effect as -x on its own, so wecan treat them as the same. */static const char *prefix[] = { "", "\\b", "^(?:", "^(?:", "\\Q", "\\b\\Q", "^(?:\\Q", "^(?:\\Q" };static const char *suffix[] = { "", "\\b", ")$", ")$", "\\E", "\\E\\b", "\\E)$", "\\E)$" };/************************************************** OS-specific functions **************************************************//* These functions are defined so that they can be made system specific,although at present the only ones are for Unix, Win32, and for "no support". *//************* Directory scanning in Unix ***********/#if IS_UNIX#include <sys/types.h>#include <sys/stat.h>#include <dirent.h>typedef DIR directory_type;static intisdirectory(char *filename){struct stat statbuf;if (stat(filename, &statbuf) < 0) return 0; /* In the expectation that opening as a file will fail */return ((statbuf.st_mode & S_IFMT) == S_IFDIR)? '/' : 0;}static directory_type *opendirectory(char *filename){return opendir(filename);}static char *readdirectory(directory_type *dir){for (;;) { struct dirent *dent = readdir(dir); if (dent == NULL) return NULL; if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) return dent->d_name; }return NULL; /* Keep compiler happy; never executed */}static voidclosedirectory(directory_type *dir){closedir(dir);}/************* Test for regular file in Unix **********/static intisregfile(char *filename){struct stat statbuf;if (stat(filename, &statbuf) < 0) return 1; /* In the expectation that opening as a file will fail */return (statbuf.st_mode & S_IFMT) == S_IFREG;}/************* Test stdout for being a terminal in Unix **********/static BOOLis_stdout_tty(void){return isatty(fileno(stdout));}/************* Directory scanning in Win32 ***********//* I (Philip Hazel) have no means of testing this code. It was contributed byLionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTESwhen it did not exist. */#elif HAVE_WIN32API#ifndef STRICT# define STRICT#endif#ifndef WIN32_LEAN_AND_MEAN# define WIN32_LEAN_AND_MEAN#endif#ifndef INVALID_FILE_ATTRIBUTES#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF#endif#include <windows.h>typedef struct directory_type{HANDLE handle;BOOL first;WIN32_FIND_DATA data;} directory_type;intisdirectory(char *filename){DWORD attr = GetFileAttributes(filename);if (attr == INVALID_FILE_ATTRIBUTES) return 0;return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) ? '/' : 0;}directory_type *opendirectory(char *filename){size_t len;char *pattern;directory_type *dir;DWORD err;len = strlen(filename);pattern = (char *) malloc(len + 3);dir = (directory_type *) malloc(sizeof(*dir));if ((pattern == NULL) || (dir == NULL)) { fprintf(stderr, "pcregrep: malloc failed\n"); exit(2); }memcpy(pattern, filename, len);memcpy(&(pattern[len]), "\\*", 3);dir->handle = FindFirstFile(pattern, &(dir->data));if (dir->handle != INVALID_HANDLE_VALUE) { free(pattern); dir->first = TRUE; return dir; }err = GetLastError();free(pattern);free(dir);errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT;return NULL;}char *readdirectory(directory_type *dir){for (;;) { if (!dir->first) { if (!FindNextFile(dir->handle, &(dir->data))) return NULL; } else { dir->first = FALSE; } if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0) return dir->data.cFileName; }#ifndef _MSC_VERreturn NULL; /* Keep compiler happy; never executed */#endif}voidclosedirectory(directory_type *dir){FindClose(dir->handle);free(dir);}/************* Test for regular file in Win32 **********//* I don't know how to do this, or if it can be done; assume all paths areregular if they are not directories. */int isregfile(char *filename){return !isdirectory(filename)}/************* Test stdout for being a terminal in Win32 **********//* I don't know how to do this; assume never */static BOOLis_stdout_tty(void){FALSE;}/************* Directory scanning when we can't do it ***********//* The type is void, and apart from isdirectory(), the functions do nothing. */#elsetypedef void directory_type;int isdirectory(char *filename) { return 0; }directory_type * opendirectory(char *filename) {}char *readdirectory(directory_type *dir) {}void closedirectory(directory_type *dir) {}/************* Test for regular when we can't do it **********//* Assume all files are regular. */int isregfile(char *filename) { return 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -