version 1.1.1.3, 2012/10/09 09:19:17
|
version 1.1.1.4, 2013/07/22 08:25:55
|
Line 70 POSSIBILITY OF SUCH DAMAGE.
|
Line 70 POSSIBILITY OF SUCH DAMAGE.
|
|
|
typedef int BOOL; |
typedef int BOOL; |
|
|
#define MAX_PATTERN_COUNT 100 |
|
#define OFFSET_SIZE 99 |
#define OFFSET_SIZE 99 |
|
|
#if BUFSIZ > 8192 |
#if BUFSIZ > 8192 |
#define PATBUFSIZE BUFSIZ | #define MAXPATLEN BUFSIZ |
#else |
#else |
#define PATBUFSIZE 8192 | #define MAXPATLEN 8192 |
#endif |
#endif |
|
|
|
#define PATBUFSIZE (MAXPATLEN + 10) /* Allows for prefix+suffix */ |
|
|
/* Values for the "filenames" variable, which specifies options for file name |
/* Values for the "filenames" variable, which specifies options for file name |
output. The order is important; it is assumed that a file name is wanted for |
output. The order is important; it is assumed that a file name is wanted for |
all values greater than FN_DEFAULT. */ |
all values greater than FN_DEFAULT. */ |
Line 139 static char *colour_string = (char *)"1;31";
|
Line 140 static char *colour_string = (char *)"1;31";
|
static char *colour_option = NULL; |
static char *colour_option = NULL; |
static char *dee_option = NULL; |
static char *dee_option = NULL; |
static char *DEE_option = NULL; |
static char *DEE_option = NULL; |
|
static char *locale = NULL; |
static char *main_buffer = NULL; |
static char *main_buffer = NULL; |
static char *newline = NULL; |
static char *newline = NULL; |
static char *pattern_filename = NULL; | static char *om_separator = (char *)""; |
static char *stdin_name = (char *)"(standard input)"; |
static char *stdin_name = (char *)"(standard input)"; |
static char *locale = NULL; |
|
|
|
static const unsigned char *pcretables = NULL; |
static const unsigned char *pcretables = NULL; |
|
|
static int pattern_count = 0; |
|
static pcre **pattern_list = NULL; |
|
static pcre_extra **hints_list = NULL; |
|
|
|
static char *file_list = NULL; |
|
static char *include_pattern = NULL; |
|
static char *exclude_pattern = NULL; |
|
static char *include_dir_pattern = NULL; |
|
static char *exclude_dir_pattern = NULL; |
|
|
|
static pcre *include_compiled = NULL; |
|
static pcre *exclude_compiled = NULL; |
|
static pcre *include_dir_compiled = NULL; |
|
static pcre *exclude_dir_compiled = NULL; |
|
|
|
static int after_context = 0; |
static int after_context = 0; |
static int before_context = 0; |
static int before_context = 0; |
static int binary_files = BIN_BINARY; |
static int binary_files = BIN_BINARY; |
static int both_context = 0; |
static int both_context = 0; |
static int bufthird = PCREGREP_BUFSIZE; |
static int bufthird = PCREGREP_BUFSIZE; |
static int bufsize = 3*PCREGREP_BUFSIZE; |
static int bufsize = 3*PCREGREP_BUFSIZE; |
|
|
|
#if defined HAVE_WINDOWS_H && HAVE_WINDOWS_H |
|
static int dee_action = dee_SKIP; |
|
#else |
static int dee_action = dee_READ; |
static int dee_action = dee_READ; |
|
#endif |
|
|
static int DEE_action = DEE_READ; |
static int DEE_action = DEE_READ; |
static int error_count = 0; |
static int error_count = 0; |
static int filenames = FN_DEFAULT; |
static int filenames = FN_DEFAULT; |
static int only_matching = -1; | static int pcre_options = 0; |
static int process_options = 0; |
static int process_options = 0; |
|
|
#ifdef SUPPORT_PCREGREP_JIT |
#ifdef SUPPORT_PCREGREP_JIT |
Line 196 static BOOL number = FALSE;
|
Line 188 static BOOL number = FALSE;
|
static BOOL omit_zero_count = FALSE; |
static BOOL omit_zero_count = FALSE; |
static BOOL resource_error = FALSE; |
static BOOL resource_error = FALSE; |
static BOOL quiet = FALSE; |
static BOOL quiet = FALSE; |
|
static BOOL show_only_matching = FALSE; |
static BOOL silent = FALSE; |
static BOOL silent = FALSE; |
static BOOL utf8 = FALSE; |
static BOOL utf8 = FALSE; |
|
|
|
/* Structure for list of --only-matching capturing numbers. */ |
|
|
|
typedef struct omstr { |
|
struct omstr *next; |
|
int groupnum; |
|
} omstr; |
|
|
|
static omstr *only_matching = NULL; |
|
static omstr *only_matching_last = NULL; |
|
|
|
/* Structure for holding the two variables that describe a number chain. */ |
|
|
|
typedef struct omdatastr { |
|
omstr **anchor; |
|
omstr **lastptr; |
|
} omdatastr; |
|
|
|
static omdatastr only_matching_data = { &only_matching, &only_matching_last }; |
|
|
|
/* Structure for list of file names (for -f and --{in,ex}clude-from) */ |
|
|
|
typedef struct fnstr { |
|
struct fnstr *next; |
|
char *name; |
|
} fnstr; |
|
|
|
static fnstr *exclude_from = NULL; |
|
static fnstr *exclude_from_last = NULL; |
|
static fnstr *include_from = NULL; |
|
static fnstr *include_from_last = NULL; |
|
|
|
static fnstr *file_lists = NULL; |
|
static fnstr *file_lists_last = NULL; |
|
static fnstr *pattern_files = NULL; |
|
static fnstr *pattern_files_last = NULL; |
|
|
|
/* Structure for holding the two variables that describe a file name chain. */ |
|
|
|
typedef struct fndatastr { |
|
fnstr **anchor; |
|
fnstr **lastptr; |
|
} fndatastr; |
|
|
|
static fndatastr exclude_from_data = { &exclude_from, &exclude_from_last }; |
|
static fndatastr include_from_data = { &include_from, &include_from_last }; |
|
static fndatastr file_lists_data = { &file_lists, &file_lists_last }; |
|
static fndatastr pattern_files_data = { &pattern_files, &pattern_files_last }; |
|
|
|
/* Structure for pattern and its compiled form; used for matching patterns and |
|
also for include/exclude patterns. */ |
|
|
|
typedef struct patstr { |
|
struct patstr *next; |
|
char *string; |
|
pcre *compiled; |
|
pcre_extra *hint; |
|
} patstr; |
|
|
|
static patstr *patterns = NULL; |
|
static patstr *patterns_last = NULL; |
|
static patstr *include_patterns = NULL; |
|
static patstr *include_patterns_last = NULL; |
|
static patstr *exclude_patterns = NULL; |
|
static patstr *exclude_patterns_last = NULL; |
|
static patstr *include_dir_patterns = NULL; |
|
static patstr *include_dir_patterns_last = NULL; |
|
static patstr *exclude_dir_patterns = NULL; |
|
static patstr *exclude_dir_patterns_last = NULL; |
|
|
|
/* Structure holding the two variables that describe a pattern chain. A pointer |
|
to such structures is used for each appropriate option. */ |
|
|
|
typedef struct patdatastr { |
|
patstr **anchor; |
|
patstr **lastptr; |
|
} patdatastr; |
|
|
|
static patdatastr match_patdata = { &patterns, &patterns_last }; |
|
static patdatastr include_patdata = { &include_patterns, &include_patterns_last }; |
|
static patdatastr exclude_patdata = { &exclude_patterns, &exclude_patterns_last }; |
|
static patdatastr include_dir_patdata = { &include_dir_patterns, &include_dir_patterns_last }; |
|
static patdatastr exclude_dir_patdata = { &exclude_dir_patterns, &exclude_dir_patterns_last }; |
|
|
|
static patstr **incexlist[4] = { &include_patterns, &exclude_patterns, |
|
&include_dir_patterns, &exclude_dir_patterns }; |
|
|
|
static const char *incexname[4] = { "--include", "--exclude", |
|
"--include-dir", "--exclude-dir" }; |
|
|
/* Structure for options and list of them */ |
/* Structure for options and list of them */ |
|
|
enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_LONGNUMBER, |
enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_LONGNUMBER, |
OP_OP_NUMBER, OP_PATLIST, OP_BINFILES }; | OP_OP_NUMBER, OP_OP_NUMBERS, OP_PATLIST, OP_FILELIST, OP_BINFILES }; |
|
|
typedef struct option_item { |
typedef struct option_item { |
int type; |
int type; |
Line 233 used to identify them. */
|
Line 315 used to identify them. */
|
#define N_NOJIT (-16) |
#define N_NOJIT (-16) |
#define N_FILE_LIST (-17) |
#define N_FILE_LIST (-17) |
#define N_BINARY_FILES (-18) |
#define N_BINARY_FILES (-18) |
|
#define N_EXCLUDE_FROM (-19) |
|
#define N_INCLUDE_FROM (-20) |
|
#define N_OM_SEPARATOR (-21) |
|
|
static option_item optionlist[] = { |
static option_item optionlist[] = { |
{ OP_NODATA, N_NULL, NULL, "", "terminate options" }, |
{ OP_NODATA, N_NULL, NULL, "", "terminate options" }, |
Line 248 static option_item optionlist[] = {
|
Line 333 static option_item optionlist[] = {
|
{ OP_NODATA, 'c', NULL, "count", "print only a count of matching lines per FILE" }, |
{ OP_NODATA, 'c', NULL, "count", "print only a count of matching lines per FILE" }, |
{ OP_STRING, 'D', &DEE_option, "devices=action","how to handle devices, FIFOs, and sockets" }, |
{ 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_STRING, 'd', &dee_option, "directories=action", "how to handle directories" }, |
{ OP_PATLIST, 'e', NULL, "regex(p)=pattern", "specify pattern (may be used more than once)" }, | { OP_PATLIST, 'e', &match_patdata, "regex(p)=pattern", "specify pattern (may be used more than once)" }, |
{ OP_NODATA, 'F', NULL, "fixed-strings", "patterns are sets of newline-separated strings" }, |
{ 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_FILELIST, 'f', &pattern_files_data, "file=path", "read patterns from file" }, |
{ OP_STRING, N_FILE_LIST, &file_list, "file-list=path","read files to search from file" }, | { OP_FILELIST, N_FILE_LIST, &file_lists_data, "file-list=path","read files to search from file" }, |
{ OP_NODATA, N_FOFFSETS, NULL, "file-offsets", "output file offsets, not text" }, |
{ OP_NODATA, N_FOFFSETS, NULL, "file-offsets", "output file offsets, not text" }, |
{ OP_NODATA, 'H', NULL, "with-filename", "force the prefixing filename on output" }, |
{ 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, 'h', NULL, "no-filename", "suppress the prefixing filename on output" }, |
Line 273 static option_item optionlist[] = {
|
Line 358 static option_item optionlist[] = {
|
{ OP_NODATA, 'M', NULL, "multiline", "run in multiline mode" }, |
{ OP_NODATA, 'M', NULL, "multiline", "run in multiline mode" }, |
{ OP_STRING, 'N', &newline, "newline=type", "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" }, |
{ OP_STRING, 'N', &newline, "newline=type", "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" }, |
{ OP_NODATA, 'n', NULL, "line-number", "print line number with output lines" }, |
{ OP_NODATA, 'n', NULL, "line-number", "print line number with output lines" }, |
{ OP_OP_NUMBER, 'o', &only_matching, "only-matching=n", "show only the part of the line that matched" }, | { OP_OP_NUMBERS, 'o', &only_matching_data, "only-matching=n", "show only the part of the line that matched" }, |
| { OP_STRING, N_OM_SEPARATOR, &om_separator, "om-separator=text", "set separator for multiple -o output" }, |
{ OP_NODATA, 'q', NULL, "quiet", "suppress output, just set return code" }, |
{ OP_NODATA, 'q', NULL, "quiet", "suppress output, just set return code" }, |
{ OP_NODATA, 'r', NULL, "recursive", "recursively scan sub-directories" }, |
{ OP_NODATA, 'r', NULL, "recursive", "recursively scan sub-directories" }, |
{ OP_STRING, N_EXCLUDE,&exclude_pattern, "exclude=pattern","exclude matching files when recursing" }, | { OP_PATLIST, N_EXCLUDE,&exclude_patdata, "exclude=pattern","exclude matching files when recursing" }, |
{ OP_STRING, N_INCLUDE,&include_pattern, "include=pattern","include matching files when recursing" }, | { OP_PATLIST, N_INCLUDE,&include_patdata, "include=pattern","include matching files when recursing" }, |
{ OP_STRING, N_EXCLUDE_DIR,&exclude_dir_pattern, "exclude-dir=pattern","exclude matching directories when recursing" }, | { OP_PATLIST, N_EXCLUDE_DIR,&exclude_dir_patdata, "exclude-dir=pattern","exclude matching directories when recursing" }, |
{ OP_STRING, N_INCLUDE_DIR,&include_dir_pattern, "include-dir=pattern","include matching directories when recursing" }, | { OP_PATLIST, N_INCLUDE_DIR,&include_dir_patdata, "include-dir=pattern","include matching directories when recursing" }, |
| { OP_FILELIST, N_EXCLUDE_FROM,&exclude_from_data, "exclude-from=path", "read exclude list from file" }, |
| { OP_FILELIST, N_INCLUDE_FROM,&include_from_data, "include-from=path", "read include list from file" }, |
|
|
/* These two were accidentally implemented with underscores instead of |
/* These two were accidentally implemented with underscores instead of |
hyphens in the option names. As this was not discovered for several releases, |
hyphens in the option names. As this was not discovered for several releases, |
the incorrect versions are left in the table for compatibility. However, the |
the incorrect versions are left in the table for compatibility. However, the |
--help function misses out any option that has an underscore in its name. */ |
--help function misses out any option that has an underscore in its name. */ |
|
|
{ OP_STRING, N_EXCLUDE_DIR,&exclude_dir_pattern, "exclude_dir=pattern","exclude matching directories when recursing" }, | { OP_PATLIST, N_EXCLUDE_DIR,&exclude_dir_patdata, "exclude_dir=pattern","exclude matching directories when recursing" }, |
{ OP_STRING, N_INCLUDE_DIR,&include_dir_pattern, "include_dir=pattern","include matching directories when recursing" }, | { OP_PATLIST, N_INCLUDE_DIR,&include_dir_patdata, "include_dir=pattern","include matching directories when recursing" }, |
|
|
#ifdef JFRIEDL_DEBUG |
#ifdef JFRIEDL_DEBUG |
{ OP_OP_NUMBER, 'S', &S_arg, "jeffS", "replace matched (sub)string with X" }, |
{ OP_OP_NUMBER, 'S', &S_arg, "jeffS", "replace matched (sub)string with X" }, |
Line 304 static option_item optionlist[] = {
|
Line 392 static option_item optionlist[] = {
|
/* Tables for prefixing and suffixing patterns, according to the -w, -x, and -F |
/* Tables for prefixing and suffixing patterns, according to the -w, -x, and -F |
options. These set the 1, 2, and 4 bits in process_options, respectively. Note |
options. These set the 1, 2, and 4 bits in process_options, respectively. Note |
that the combination of -w and -x has the same effect as -x on its own, so we |
that the combination of -w and -x has the same effect as -x on its own, so we |
can treat them as the same. */ | can treat them as the same. Note that the MAXPATLEN macro assumes the longest |
| prefix+suffix is 10 characters; if anything longer is added, it must be |
| adjusted. */ |
|
|
static const char *prefix[] = { |
static const char *prefix[] = { |
"", "\\b", "^(?:", "^(?:", "\\Q", "\\b\\Q", "^(?:\\Q", "^(?:\\Q" }; |
"", "\\b", "^(?:", "^(?:", "\\Q", "\\b\\Q", "^(?:\\Q", "^(?:\\Q" }; |
Line 344 if (resource_error)
|
Line 434 if (resource_error)
|
PCRE_ERROR_JIT_STACKLIMIT); |
PCRE_ERROR_JIT_STACKLIMIT); |
fprintf(stderr, "pcregrep: Check your regex for nested unlimited loops.\n"); |
fprintf(stderr, "pcregrep: Check your regex for nested unlimited loops.\n"); |
} |
} |
|
|
exit(rc); |
exit(rc); |
} |
} |
|
|
|
|
/************************************************* |
/************************************************* |
|
* Add item to chain of patterns * |
|
*************************************************/ |
|
|
|
/* Used to add an item onto a chain, or just return an unconnected item if the |
|
"after" argument is NULL. |
|
|
|
Arguments: |
|
s pattern string to add |
|
after if not NULL points to item to insert after |
|
|
|
Returns: new pattern block |
|
*/ |
|
|
|
static patstr * |
|
add_pattern(char *s, patstr *after) |
|
{ |
|
patstr *p = (patstr *)malloc(sizeof(patstr)); |
|
if (p == NULL) |
|
{ |
|
fprintf(stderr, "pcregrep: malloc failed\n"); |
|
pcregrep_exit(2); |
|
} |
|
if (strlen(s) > MAXPATLEN) |
|
{ |
|
fprintf(stderr, "pcregrep: pattern is too long (limit is %d bytes)\n", |
|
MAXPATLEN); |
|
return NULL; |
|
} |
|
p->next = NULL; |
|
p->string = s; |
|
p->compiled = NULL; |
|
p->hint = NULL; |
|
|
|
if (after != NULL) |
|
{ |
|
p->next = after->next; |
|
after->next = p; |
|
} |
|
return p; |
|
} |
|
|
|
|
|
/************************************************* |
|
* Free chain of patterns * |
|
*************************************************/ |
|
|
|
/* Used for several chains of patterns. |
|
|
|
Argument: pointer to start of chain |
|
Returns: nothing |
|
*/ |
|
|
|
static void |
|
free_pattern_chain(patstr *pc) |
|
{ |
|
while (pc != NULL) |
|
{ |
|
patstr *p = pc; |
|
pc = p->next; |
|
if (p->hint != NULL) pcre_free_study(p->hint); |
|
if (p->compiled != NULL) pcre_free(p->compiled); |
|
free(p); |
|
} |
|
} |
|
|
|
|
|
/************************************************* |
|
* Free chain of file names * |
|
*************************************************/ |
|
|
|
/* |
|
Argument: pointer to start of chain |
|
Returns: nothing |
|
*/ |
|
|
|
static void |
|
free_file_chain(fnstr *fn) |
|
{ |
|
while (fn != NULL) |
|
{ |
|
fnstr *f = fn; |
|
fn = f->next; |
|
free(f); |
|
} |
|
} |
|
|
|
|
|
/************************************************* |
* OS-specific functions * |
* OS-specific functions * |
*************************************************/ |
*************************************************/ |
|
|
Line 365 although at present the only ones are for Unix, Win32,
|
Line 542 although at present the only ones are for Unix, Win32,
|
#include <dirent.h> |
#include <dirent.h> |
|
|
typedef DIR directory_type; |
typedef DIR directory_type; |
|
#define FILESEP '/' |
|
|
static int |
static int |
isdirectory(char *filename) |
isdirectory(char *filename) |
Line 372 isdirectory(char *filename)
|
Line 550 isdirectory(char *filename)
|
struct stat statbuf; |
struct stat statbuf; |
if (stat(filename, &statbuf) < 0) |
if (stat(filename, &statbuf) < 0) |
return 0; /* In the expectation that opening as a file will fail */ |
return 0; /* In the expectation that opening as a file will fail */ |
return ((statbuf.st_mode & S_IFMT) == S_IFDIR)? '/' : 0; | return (statbuf.st_mode & S_IFMT) == S_IFDIR; |
} |
} |
|
|
static directory_type * |
static directory_type * |
Line 459 BOOL first;
|
Line 637 BOOL first;
|
WIN32_FIND_DATA data; |
WIN32_FIND_DATA data; |
} directory_type; |
} directory_type; |
|
|
|
#define FILESEP '/' |
|
|
int |
int |
isdirectory(char *filename) |
isdirectory(char *filename) |
{ |
{ |
DWORD attr = GetFileAttributes(filename); |
DWORD attr = GetFileAttributes(filename); |
if (attr == INVALID_FILE_ATTRIBUTES) |
if (attr == INVALID_FILE_ATTRIBUTES) |
return 0; |
return 0; |
return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) ? '/' : 0; | return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; |
} |
} |
|
|
directory_type * |
directory_type * |
Line 476 char *pattern;
|
Line 656 char *pattern;
|
directory_type *dir; |
directory_type *dir; |
DWORD err; |
DWORD err; |
len = strlen(filename); |
len = strlen(filename); |
pattern = (char *) malloc(len + 3); | pattern = (char *)malloc(len + 3); |
dir = (directory_type *) malloc(sizeof(*dir)); | dir = (directory_type *)malloc(sizeof(*dir)); |
if ((pattern == NULL) || (dir == NULL)) |
if ((pattern == NULL) || (dir == NULL)) |
{ |
{ |
fprintf(stderr, "pcregrep: malloc failed\n"); |
fprintf(stderr, "pcregrep: malloc failed\n"); |
Line 563 return FALSE;
|
Line 743 return FALSE;
|
|
|
#else |
#else |
|
|
|
#define FILESEP 0 |
typedef void directory_type; |
typedef void directory_type; |
|
|
int isdirectory(char *filename) { return 0; } |
int isdirectory(char *filename) { return 0; } |
Line 619 return sys_errlist[n];
|
Line 800 return sys_errlist[n];
|
|
|
|
|
/************************************************* |
/************************************************* |
|
* Usage function * |
|
*************************************************/ |
|
|
|
static int |
|
usage(int rc) |
|
{ |
|
option_item *op; |
|
fprintf(stderr, "Usage: pcregrep [-"); |
|
for (op = optionlist; op->one_char != 0; op++) |
|
{ |
|
if (op->one_char > 0) fprintf(stderr, "%c", op->one_char); |
|
} |
|
fprintf(stderr, "] [long options] [pattern] [files]\n"); |
|
fprintf(stderr, "Type `pcregrep --help' for more information and the long " |
|
"options.\n"); |
|
return rc; |
|
} |
|
|
|
|
|
|
|
/************************************************* |
|
* Help function * |
|
*************************************************/ |
|
|
|
static void |
|
help(void) |
|
{ |
|
option_item *op; |
|
|
|
printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n"); |
|
printf("Search for PATTERN in each FILE or standard input.\n"); |
|
printf("PATTERN must be present if neither -e nor -f is used.\n"); |
|
printf("\"-\" can be used as a file name to mean STDIN.\n"); |
|
|
|
#ifdef SUPPORT_LIBZ |
|
printf("Files whose names end in .gz are read using zlib.\n"); |
|
#endif |
|
|
|
#ifdef SUPPORT_LIBBZ2 |
|
printf("Files whose names end in .bz2 are read using bzlib2.\n"); |
|
#endif |
|
|
|
#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2 |
|
printf("Other files and the standard input are read as plain files.\n\n"); |
|
#else |
|
printf("All files are read as plain files, without any interpretation.\n\n"); |
|
#endif |
|
|
|
printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n"); |
|
printf("Options:\n"); |
|
|
|
for (op = optionlist; op->one_char != 0; op++) |
|
{ |
|
int n; |
|
char s[4]; |
|
|
|
/* Two options were accidentally implemented and documented with underscores |
|
instead of hyphens in their names, something that was not noticed for quite a |
|
few releases. When fixing this, I left the underscored versions in the list |
|
in case people were using them. However, we don't want to display them in the |
|
help data. There are no other options that contain underscores, and we do not |
|
expect ever to implement such options. Therefore, just omit any option that |
|
contains an underscore. */ |
|
|
|
if (strchr(op->long_name, '_') != NULL) continue; |
|
|
|
if (op->one_char > 0 && (op->long_name)[0] == 0) |
|
n = 31 - printf(" -%c", op->one_char); |
|
else |
|
{ |
|
if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); |
|
else strcpy(s, " "); |
|
n = 31 - printf(" %s --%s", s, op->long_name); |
|
} |
|
|
|
if (n < 1) n = 1; |
|
printf("%.*s%s\n", n, " ", op->help_text); |
|
} |
|
|
|
printf("\nNumbers may be followed by K or M, e.g. --buffer-size=100K.\n"); |
|
printf("The default value for --buffer-size is %d.\n", PCREGREP_BUFSIZE); |
|
printf("When reading patterns or file names from a file, trailing white\n"); |
|
printf("space is removed and blank lines are ignored.\n"); |
|
printf("The maximum size of any pattern is %d bytes.\n", MAXPATLEN); |
|
|
|
printf("\nWith no FILEs, read standard input. If fewer than two FILEs given, assume -h.\n"); |
|
printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble.\n"); |
|
} |
|
|
|
|
|
|
|
/************************************************* |
|
* Test exclude/includes * |
|
*************************************************/ |
|
|
|
/* If any exclude pattern matches, the path is excluded. Otherwise, unless |
|
there are no includes, the path must match an include pattern. |
|
|
|
Arguments: |
|
path the path to be matched |
|
ip the chain of include patterns |
|
ep the chain of exclude patterns |
|
|
|
Returns: TRUE if the path is not excluded |
|
*/ |
|
|
|
static BOOL |
|
test_incexc(char *path, patstr *ip, patstr *ep) |
|
{ |
|
int plen = strlen(path); |
|
|
|
for (; ep != NULL; ep = ep->next) |
|
{ |
|
if (pcre_exec(ep->compiled, NULL, path, plen, 0, 0, NULL, 0) >= 0) |
|
return FALSE; |
|
} |
|
|
|
if (ip == NULL) return TRUE; |
|
|
|
for (; ip != NULL; ip = ip->next) |
|
{ |
|
if (pcre_exec(ip->compiled, NULL, path, plen, 0, 0, NULL, 0) >= 0) |
|
return TRUE; |
|
} |
|
|
|
return FALSE; |
|
} |
|
|
|
|
|
|
|
/************************************************* |
|
* Decode integer argument value * |
|
*************************************************/ |
|
|
|
/* Integer arguments can be followed by K or M. Avoid the use of strtoul() |
|
because SunOS4 doesn't have it. This is used only for unpicking arguments, so |
|
just keep it simple. |
|
|
|
Arguments: |
|
option_data the option data string |
|
op the option item (for error messages) |
|
longop TRUE if option given in long form |
|
|
|
Returns: a long integer |
|
*/ |
|
|
|
static long int |
|
decode_number(char *option_data, option_item *op, BOOL longop) |
|
{ |
|
unsigned long int n = 0; |
|
char *endptr = option_data; |
|
while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++; |
|
while (isdigit((unsigned char)(*endptr))) |
|
n = n * 10 + (int)(*endptr++ - '0'); |
|
if (toupper(*endptr) == 'K') |
|
{ |
|
n *= 1024; |
|
endptr++; |
|
} |
|
else if (toupper(*endptr) == 'M') |
|
{ |
|
n *= 1024*1024; |
|
endptr++; |
|
} |
|
|
|
if (*endptr != 0) /* Error */ |
|
{ |
|
if (longop) |
|
{ |
|
char *equals = strchr(op->long_name, '='); |
|
int nlen = (equals == NULL)? (int)strlen(op->long_name) : |
|
(int)(equals - op->long_name); |
|
fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n", |
|
option_data, nlen, op->long_name); |
|
} |
|
else |
|
fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n", |
|
option_data, op->one_char); |
|
pcregrep_exit(usage(2)); |
|
} |
|
|
|
return n; |
|
} |
|
|
|
|
|
|
|
/************************************************* |
|
* Add item to a chain of numbers * |
|
*************************************************/ |
|
|
|
/* Used to add an item onto a chain, or just return an unconnected item if the |
|
"after" argument is NULL. |
|
|
|
Arguments: |
|
n the number to add |
|
after if not NULL points to item to insert after |
|
|
|
Returns: new number block |
|
*/ |
|
|
|
static omstr * |
|
add_number(int n, omstr *after) |
|
{ |
|
omstr *om = (omstr *)malloc(sizeof(omstr)); |
|
|
|
if (om == NULL) |
|
{ |
|
fprintf(stderr, "pcregrep: malloc failed\n"); |
|
pcregrep_exit(2); |
|
} |
|
om->next = NULL; |
|
om->groupnum = n; |
|
|
|
if (after != NULL) |
|
{ |
|
om->next = after->next; |
|
after->next = om; |
|
} |
|
return om; |
|
} |
|
|
|
|
|
|
|
/************************************************* |
* Read one line of input * |
* Read one line of input * |
*************************************************/ |
*************************************************/ |
|
|
Line 734 switch(endlinetype)
|
Line 1139 switch(endlinetype)
|
|
|
switch (c) |
switch (c) |
{ |
{ |
case 0x0a: /* LF */ | case '\n': |
*lenptr = 1; |
*lenptr = 1; |
return p; |
return p; |
|
|
case 0x0d: /* CR */ | case '\r': |
if (p < endptr && *p == 0x0a) | if (p < endptr && *p == '\n') |
{ |
{ |
*lenptr = 2; |
*lenptr = 2; |
p++; |
p++; |
Line 778 switch(endlinetype)
|
Line 1183 switch(endlinetype)
|
|
|
switch (c) |
switch (c) |
{ |
{ |
case 0x0a: /* LF */ | case '\n': /* LF */ |
case 0x0b: /* VT */ | case '\v': /* VT */ |
case 0x0c: /* FF */ | case '\f': /* FF */ |
*lenptr = 1; |
*lenptr = 1; |
return p; |
return p; |
|
|
case 0x0d: /* CR */ | case '\r': /* CR */ |
if (p < endptr && *p == 0x0a) | if (p < endptr && *p == '\n') |
{ |
{ |
*lenptr = 2; |
*lenptr = 2; |
p++; |
p++; |
Line 793 switch(endlinetype)
|
Line 1198 switch(endlinetype)
|
else *lenptr = 1; |
else *lenptr = 1; |
return p; |
return p; |
|
|
case 0x85: /* NEL */ | #ifndef EBCDIC |
| case 0x85: /* Unicode NEL */ |
*lenptr = utf8? 2 : 1; |
*lenptr = utf8? 2 : 1; |
return p; |
return p; |
|
|
case 0x2028: /* LS */ | case 0x2028: /* Unicode LS */ |
case 0x2029: /* PS */ | case 0x2029: /* Unicode PS */ |
*lenptr = 3; |
*lenptr = 3; |
return p; |
return p; |
|
#endif /* Not EBCDIC */ |
|
|
default: |
default: |
break; |
break; |
Line 859 switch(endlinetype)
|
Line 1266 switch(endlinetype)
|
|
|
while (p > startptr) |
while (p > startptr) |
{ |
{ |
register int c; | register unsigned int c; |
char *pp = p - 1; |
char *pp = p - 1; |
|
|
if (utf8) |
if (utf8) |
Line 884 switch(endlinetype)
|
Line 1291 switch(endlinetype)
|
|
|
if (endlinetype == EL_ANYCRLF) switch (c) |
if (endlinetype == EL_ANYCRLF) switch (c) |
{ |
{ |
case 0x0a: /* LF */ | case '\n': /* LF */ |
case 0x0d: /* CR */ | case '\r': /* CR */ |
return p; |
return p; |
|
|
default: |
default: |
Line 894 switch(endlinetype)
|
Line 1301 switch(endlinetype)
|
|
|
else switch (c) |
else switch (c) |
{ |
{ |
case 0x0a: /* LF */ | case '\n': /* LF */ |
case 0x0b: /* VT */ | case '\v': /* VT */ |
case 0x0c: /* FF */ | case '\f': /* FF */ |
case 0x0d: /* CR */ | case '\r': /* CR */ |
case 0x85: /* NEL */ | #ifndef EBCDIE |
case 0x2028: /* LS */ | case 0x85: /* Unicode NEL */ |
case 0x2029: /* PS */ | case 0x2028: /* Unicode LS */ |
| case 0x2029: /* Unicode PS */ |
| #endif /* Not EBCDIC */ |
return p; |
return p; |
|
|
default: |
default: |
Line 935 Arguments:
|
Line 1344 Arguments:
|
Returns: nothing |
Returns: nothing |
*/ |
*/ |
|
|
static void do_after_lines(int lastmatchnumber, char *lastmatchrestart, | static void |
char *endptr, char *printname) | do_after_lines(int lastmatchnumber, char *lastmatchrestart, char *endptr, |
| char *printname) |
{ |
{ |
if (after_context > 0 && lastmatchnumber > 0) |
if (after_context > 0 && lastmatchnumber > 0) |
{ |
{ |
Line 968 to find all possible matches.
|
Line 1378 to find all possible matches.
|
Arguments: |
Arguments: |
matchptr the start of the subject |
matchptr the start of the subject |
length the length of the subject to match |
length the length of the subject to match |
|
options options for pcre_exec |
startoffset where to start matching |
startoffset where to start matching |
offsets the offets vector to fill in |
offsets the offets vector to fill in |
mrc address of where to put the result of pcre_exec() |
mrc address of where to put the result of pcre_exec() |
Line 978 Returns: TRUE if there was a match
|
Line 1389 Returns: TRUE if there was a match
|
*/ |
*/ |
|
|
static BOOL |
static BOOL |
match_patterns(char *matchptr, size_t length, int startoffset, int *offsets, | match_patterns(char *matchptr, size_t length, unsigned int options, |
int *mrc) | int startoffset, int *offsets, int *mrc) |
{ |
{ |
int i; |
int i; |
size_t slen = length; |
size_t slen = length; |
|
patstr *p = patterns; |
const char *msg = "this text:\n\n"; |
const char *msg = "this text:\n\n"; |
|
|
if (slen > 200) |
if (slen > 200) |
{ |
{ |
slen = 200; |
slen = 200; |
msg = "text that starts:\n\n"; |
msg = "text that starts:\n\n"; |
} |
} |
for (i = 0; i < pattern_count; i++) | for (i = 1; p != NULL; p = p->next, i++) |
{ |
{ |
*mrc = pcre_exec(pattern_list[i], hints_list[i], matchptr, (int)length, | *mrc = pcre_exec(p->compiled, p->hint, matchptr, (int)length, |
startoffset, PCRE_NOTEMPTY, offsets, OFFSET_SIZE); | startoffset, options, offsets, OFFSET_SIZE); |
if (*mrc >= 0) return TRUE; |
if (*mrc >= 0) return TRUE; |
if (*mrc == PCRE_ERROR_NOMATCH) continue; |
if (*mrc == PCRE_ERROR_NOMATCH) continue; |
fprintf(stderr, "pcregrep: pcre_exec() gave error %d while matching ", *mrc); |
fprintf(stderr, "pcregrep: pcre_exec() gave error %d while matching ", *mrc); |
if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1); | if (patterns->next != NULL) fprintf(stderr, "pattern number %d to ", i); |
fprintf(stderr, "%s", msg); |
fprintf(stderr, "%s", msg); |
FWRITE(matchptr, 1, slen, stderr); /* In case binary zero included */ |
FWRITE(matchptr, 1, slen, stderr); /* In case binary zero included */ |
fprintf(stderr, "\n\n"); |
fprintf(stderr, "\n\n"); |
Line 1075 of what we have. In the case of libz, a non-zipped .gz
|
Line 1488 of what we have. In the case of libz, a non-zipped .gz
|
plain file. However, if a .bz2 file isn't actually bzipped, the first read will |
plain file. However, if a .bz2 file isn't actually bzipped, the first read will |
fail. */ |
fail. */ |
|
|
|
(void)frtype; |
|
|
#ifdef SUPPORT_LIBZ |
#ifdef SUPPORT_LIBZ |
if (frtype == FR_LIBZ) |
if (frtype == FR_LIBZ) |
{ |
{ |
Line 1125 while (ptr < endptr)
|
Line 1540 while (ptr < endptr)
|
int endlinelength; |
int endlinelength; |
int mrc = 0; |
int mrc = 0; |
int startoffset = 0; |
int startoffset = 0; |
|
unsigned int options = 0; |
BOOL match; |
BOOL match; |
char *matchptr = ptr; |
char *matchptr = ptr; |
char *t = ptr; |
char *t = ptr; |
Line 1161 while (ptr < endptr)
|
Line 1577 while (ptr < endptr)
|
#ifdef JFRIEDL_DEBUG |
#ifdef JFRIEDL_DEBUG |
if (jfriedl_XT || jfriedl_XR) |
if (jfriedl_XT || jfriedl_XR) |
{ |
{ |
#include <sys/time.h> | # include <sys/time.h> |
#include <time.h> | # include <time.h> |
struct timeval start_time, end_time; |
struct timeval start_time, end_time; |
struct timezone dummy; |
struct timezone dummy; |
int i; |
int i; |
Line 1191 while (ptr < endptr)
|
Line 1607 while (ptr < endptr)
|
|
|
|
|
for (i = 0; i < jfriedl_XR; i++) |
for (i = 0; i < jfriedl_XR; i++) |
match = (pcre_exec(pattern_list[0], hints_list[0], ptr, length, 0, | match = (pcre_exec(patterns->compiled, patterns->hint, ptr, length, 0, |
PCRE_NOTEMPTY, offsets, OFFSET_SIZE) >= 0); |
PCRE_NOTEMPTY, offsets, OFFSET_SIZE) >= 0); |
|
|
if (gettimeofday(&end_time, &dummy) != 0) |
if (gettimeofday(&end_time, &dummy) != 0) |
Line 1206 while (ptr < endptr)
|
Line 1622 while (ptr < endptr)
|
} |
} |
#endif |
#endif |
|
|
/* We come back here after a match when the -o option (only_matching) is set, | /* We come back here after a match when show_only_matching is set, in order |
in order to find any further matches in the same line. */ | to find any further matches in the same line. This applies to |
| --only-matching, --file-offsets, and --line-offsets. */ |
|
|
ONLY_MATCHING_RESTART: |
ONLY_MATCHING_RESTART: |
|
|
/* Run through all the patterns until one matches or there is an error other |
/* Run through all the patterns until one matches or there is an error other |
than NOMATCH. This code is in a subroutine so that it can be re-used for |
than NOMATCH. This code is in a subroutine so that it can be re-used for |
finding subsequent matches when colouring matched lines. */ | finding subsequent matches when colouring matched lines. After finding one |
| match, set PCRE_NOTEMPTY to disable any further matches of null strings in |
| this line. */ |
|
|
match = match_patterns(matchptr, length, startoffset, offsets, &mrc); | match = match_patterns(matchptr, length, options, startoffset, offsets, &mrc); |
| options = PCRE_NOTEMPTY; |
|
|
/* If it's a match or a not-match (as required), do what's wanted. */ |
/* If it's a match or a not-match (as required), do what's wanted. */ |
|
|
Line 1254 while (ptr < endptr)
|
Line 1674 while (ptr < endptr)
|
|
|
else if (quiet) return 0; |
else if (quiet) return 0; |
|
|
/* The --only-matching option prints just the substring that matched, or a | /* The --only-matching option prints just the substring that matched, |
captured portion of it, as long as this string is not empty, and the | and/or one or more captured portions of it, as long as these strings are |
--file-offsets and --line-offsets options output offsets for the matching | not empty. The --file-offsets and --line-offsets options output offsets for |
substring (they both force --only-matching = 0). None of these options | the matching substring (all three set show_only_matching). None of these |
prints any context. Afterwards, adjust the start and then jump back to look | mutually exclusive options prints any context. Afterwards, adjust the start |
for further matches in the same line. If we are in invert mode, however, | and then jump back to look for further matches in the same line. If we are |
nothing is printed and we do not restart - this could still be useful | in invert mode, however, nothing is printed and we do not restart - this |
because the return code is set. */ | could still be useful because the return code is set. */ |
|
|
else if (only_matching >= 0) | else if (show_only_matching) |
{ |
{ |
if (!invert) |
if (!invert) |
{ |
{ |
if (printname != NULL) fprintf(stdout, "%s:", printname); |
if (printname != NULL) fprintf(stdout, "%s:", printname); |
if (number) fprintf(stdout, "%d:", linenumber); |
if (number) fprintf(stdout, "%d:", linenumber); |
|
|
|
/* Handle --line-offsets */ |
|
|
if (line_offsets) |
if (line_offsets) |
fprintf(stdout, "%d,%d\n", (int)(matchptr + offsets[0] - ptr), |
fprintf(stdout, "%d,%d\n", (int)(matchptr + offsets[0] - ptr), |
offsets[1] - offsets[0]); |
offsets[1] - offsets[0]); |
|
|
|
/* Handle --file-offsets */ |
|
|
else if (file_offsets) |
else if (file_offsets) |
fprintf(stdout, "%d,%d\n", |
fprintf(stdout, "%d,%d\n", |
(int)(filepos + matchptr + offsets[0] - ptr), |
(int)(filepos + matchptr + offsets[0] - ptr), |
offsets[1] - offsets[0]); |
offsets[1] - offsets[0]); |
else if (only_matching < mrc) | |
| /* Handle --only-matching, which may occur many times */ |
| |
| else |
{ |
{ |
int plen = offsets[2*only_matching + 1] - offsets[2*only_matching]; | BOOL printed = FALSE; |
if (plen > 0) | omstr *om; |
| |
| for (om = only_matching; om != NULL; om = om->next) |
{ |
{ |
if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string); | int n = om->groupnum; |
FWRITE(matchptr + offsets[only_matching*2], 1, plen, stdout); | if (n < mrc) |
if (do_colour) fprintf(stdout, "%c[00m", 0x1b); | { |
fprintf(stdout, "\n"); | int plen = offsets[2*n + 1] - offsets[2*n]; |
| if (plen > 0) |
| { |
| if (printed) fprintf(stdout, "%s", om_separator); |
| if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string); |
| FWRITE(matchptr + offsets[n*2], 1, plen, stdout); |
| if (do_colour) fprintf(stdout, "%c[00m", 0x1b); |
| printed = TRUE; |
| } |
| } |
} |
} |
|
|
|
if (printed || printname != NULL || number) fprintf(stdout, "\n"); |
} |
} |
else if (printname != NULL || number) fprintf(stdout, "\n"); | |
| /* Prepare to repeat to find the next match */ |
| |
match = FALSE; |
match = FALSE; |
if (line_buffered) fflush(stdout); |
if (line_buffered) fflush(stdout); |
rc = 0; /* Had some success */ |
rc = 0; /* Had some success */ |
Line 1432 while (ptr < endptr)
|
Line 1876 while (ptr < endptr)
|
{ |
{ |
startoffset = offsets[1]; |
startoffset = offsets[1]; |
if (startoffset >= (int)linelength + endlinelength || |
if (startoffset >= (int)linelength + endlinelength || |
!match_patterns(matchptr, length, startoffset, offsets, &mrc)) | !match_patterns(matchptr, length, options, startoffset, offsets, |
| &mrc)) |
break; |
break; |
FWRITE(matchptr + startoffset, 1, offsets[0] - startoffset, stdout); |
FWRITE(matchptr + startoffset, 1, offsets[0] - startoffset, stdout); |
fprintf(stdout, "%c[%sm", 0x1b, colour_string); |
fprintf(stdout, "%c[%sm", 0x1b, colour_string); |
Line 1550 while (ptr < endptr)
|
Line 1995 while (ptr < endptr)
|
/* End of file; print final "after" lines if wanted; do_after_lines sets |
/* End of file; print final "after" lines if wanted; do_after_lines sets |
hyphenpending if it prints something. */ |
hyphenpending if it prints something. */ |
|
|
if (only_matching < 0 && !count_only) | if (!show_only_matching && !count_only) |
{ |
{ |
do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname); |
do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname); |
hyphenpending |= endhyphenpending; |
hyphenpending |= endhyphenpending; |
Line 1594 Arguments:
|
Line 2039 Arguments:
|
dir_recurse TRUE if recursing is wanted (-r or -drecurse) |
dir_recurse TRUE if recursing is wanted (-r or -drecurse) |
only_one_at_top TRUE if the path is the only one at toplevel |
only_one_at_top TRUE if the path is the only one at toplevel |
|
|
Returns: 0 if there was at least one match | Returns: -1 the file/directory was skipped |
| 0 if there was at least one match |
1 if there were no matches |
1 if there were no matches |
2 there was some kind of error |
2 there was some kind of error |
|
|
Line 1605 static int
|
Line 2051 static int
|
grep_or_recurse(char *pathname, BOOL dir_recurse, BOOL only_one_at_top) |
grep_or_recurse(char *pathname, BOOL dir_recurse, BOOL only_one_at_top) |
{ |
{ |
int rc = 1; |
int rc = 1; |
int sep; |
|
int frtype; |
int frtype; |
void *handle; |
void *handle; |
|
char *lastcomp; |
FILE *in = NULL; /* Ensure initialized */ |
FILE *in = NULL; /* Ensure initialized */ |
|
|
#ifdef SUPPORT_LIBZ |
#ifdef SUPPORT_LIBZ |
Line 1631 if (strcmp(pathname, "-") == 0)
|
Line 2077 if (strcmp(pathname, "-") == 0)
|
stdin_name : NULL); |
stdin_name : NULL); |
} |
} |
|
|
/* If the file is a directory, skip if skipping or if we are recursing, scan | /* Inclusion and exclusion: --include-dir and --exclude-dir apply only to |
each file and directory within it, subject to any include or exclude patterns | directories, whereas --include and --exclude apply to everything else. The test |
that were set. The scanning code is localized so it can be made | is against the final component of the path. */ |
system-specific. */ | |
|
|
if ((sep = isdirectory(pathname)) != 0) | lastcomp = strrchr(pathname, FILESEP); |
| lastcomp = (lastcomp == NULL)? pathname : lastcomp + 1; |
| |
| /* If the file is a directory, skip if not recursing or if explicitly excluded. |
| Otherwise, scan the directory and recurse for each path within it. The scanning |
| code is localized so it can be made system-specific. */ |
| |
| if (isdirectory(pathname)) |
{ |
{ |
if (dee_action == dee_SKIP) return 1; | if (dee_action == dee_SKIP || |
| !test_incexc(lastcomp, include_dir_patterns, exclude_dir_patterns)) |
| return -1; |
| |
if (dee_action == dee_RECURSE) |
if (dee_action == dee_RECURSE) |
{ |
{ |
char buffer[1024]; |
char buffer[1024]; |
Line 1655 if ((sep = isdirectory(pathname)) != 0)
|
Line 2110 if ((sep = isdirectory(pathname)) != 0)
|
|
|
while ((nextfile = readdirectory(dir)) != NULL) |
while ((nextfile = readdirectory(dir)) != NULL) |
{ |
{ |
int frc, nflen; | int frc; |
sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile); | sprintf(buffer, "%.512s%c%.128s", pathname, FILESEP, nextfile); |
nflen = (int)(strlen(nextfile)); | |
| |
if (isdirectory(buffer)) | |
{ | |
if (exclude_dir_compiled != NULL && | |
pcre_exec(exclude_dir_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) >= 0) | |
continue; | |
| |
if (include_dir_compiled != NULL && | |
pcre_exec(include_dir_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) < 0) | |
continue; | |
} | |
else | |
{ | |
if (exclude_compiled != NULL && | |
pcre_exec(exclude_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) >= 0) | |
continue; | |
| |
if (include_compiled != NULL && | |
pcre_exec(include_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) < 0) | |
continue; | |
} | |
| |
frc = grep_or_recurse(buffer, dir_recurse, FALSE); |
frc = grep_or_recurse(buffer, dir_recurse, FALSE); |
if (frc > 1) rc = frc; |
if (frc > 1) rc = frc; |
else if (frc == 0 && rc == 1) rc = 0; |
else if (frc == 0 && rc == 1) rc = 0; |
Line 1691 if ((sep = isdirectory(pathname)) != 0)
|
Line 2123 if ((sep = isdirectory(pathname)) != 0)
|
} |
} |
|
|
/* If the file is not a directory and not a regular file, skip it if that's |
/* If the file is not a directory and not a regular file, skip it if that's |
been requested. */ | been requested. Otherwise, check for explicit include/exclude. */ |
|
|
else if (!isregfile(pathname) && DEE_action == DEE_SKIP) return 1; | else if ((!isregfile(pathname) && DEE_action == DEE_SKIP) || |
| !test_incexc(lastcomp, include_patterns, exclude_patterns)) |
| return -1; |
|
|
/* Control reaches here if we have a regular file, or if we have a directory |
/* Control reaches here if we have a regular file, or if we have a directory |
and recursion or skipping was not requested, or if we have anything else and |
and recursion or skipping was not requested, or if we have anything else and |
Line 1808 return rc;
|
Line 2242 return rc;
|
|
|
|
|
|
|
|
|
/************************************************* |
/************************************************* |
* Usage function * |
|
*************************************************/ |
|
|
|
static int |
|
usage(int rc) |
|
{ |
|
option_item *op; |
|
fprintf(stderr, "Usage: pcregrep [-"); |
|
for (op = optionlist; op->one_char != 0; op++) |
|
{ |
|
if (op->one_char > 0) fprintf(stderr, "%c", op->one_char); |
|
} |
|
fprintf(stderr, "] [long options] [pattern] [files]\n"); |
|
fprintf(stderr, "Type `pcregrep --help' for more information and the long " |
|
"options.\n"); |
|
return rc; |
|
} |
|
|
|
|
|
|
|
|
|
/************************************************* |
|
* Help function * |
|
*************************************************/ |
|
|
|
static void |
|
help(void) |
|
{ |
|
option_item *op; |
|
|
|
printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n"); |
|
printf("Search for PATTERN in each FILE or standard input.\n"); |
|
printf("PATTERN must be present if neither -e nor -f is used.\n"); |
|
printf("\"-\" can be used as a file name to mean STDIN.\n"); |
|
|
|
#ifdef SUPPORT_LIBZ |
|
printf("Files whose names end in .gz are read using zlib.\n"); |
|
#endif |
|
|
|
#ifdef SUPPORT_LIBBZ2 |
|
printf("Files whose names end in .bz2 are read using bzlib2.\n"); |
|
#endif |
|
|
|
#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2 |
|
printf("Other files and the standard input are read as plain files.\n\n"); |
|
#else |
|
printf("All files are read as plain files, without any interpretation.\n\n"); |
|
#endif |
|
|
|
printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n"); |
|
printf("Options:\n"); |
|
|
|
for (op = optionlist; op->one_char != 0; op++) |
|
{ |
|
int n; |
|
char s[4]; |
|
|
|
/* Two options were accidentally implemented and documented with underscores |
|
instead of hyphens in their names, something that was not noticed for quite a |
|
few releases. When fixing this, I left the underscored versions in the list |
|
in case people were using them. However, we don't want to display them in the |
|
help data. There are no other options that contain underscores, and we do not |
|
expect ever to implement such options. Therefore, just omit any option that |
|
contains an underscore. */ |
|
|
|
if (strchr(op->long_name, '_') != NULL) continue; |
|
|
|
if (op->one_char > 0 && (op->long_name)[0] == 0) |
|
n = 31 - printf(" -%c", op->one_char); |
|
else |
|
{ |
|
if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); |
|
else strcpy(s, " "); |
|
n = 31 - printf(" %s --%s", s, op->long_name); |
|
} |
|
|
|
if (n < 1) n = 1; |
|
printf("%.*s%s\n", n, " ", op->help_text); |
|
} |
|
|
|
printf("\nNumbers may be followed by K or M, e.g. --buffer-size=100K.\n"); |
|
printf("The default value for --buffer-size is %d.\n", PCREGREP_BUFSIZE); |
|
printf("When reading patterns or file names from a file, trailing white\n"); |
|
printf("space is removed and blank lines are ignored.\n"); |
|
printf("There is a maximum of %d patterns, each of maximum size %d bytes.\n", |
|
MAX_PATTERN_COUNT, PATBUFSIZE); |
|
|
|
printf("\nWith no FILEs, read standard input. If fewer than two FILEs given, assume -h.\n"); |
|
printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble.\n"); |
|
} |
|
|
|
|
|
|
|
|
|
/************************************************* |
|
* Handle a single-letter, no data option * |
* Handle a single-letter, no data option * |
*************************************************/ |
*************************************************/ |
|
|
Line 1929 switch(letter)
|
Line 2267 switch(letter)
|
case 'L': filenames = FN_NOMATCH_ONLY; break; |
case 'L': filenames = FN_NOMATCH_ONLY; break; |
case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break; |
case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break; |
case 'n': number = TRUE; break; |
case 'n': number = TRUE; break; |
case 'o': only_matching = 0; break; | |
| case 'o': |
| only_matching_last = add_number(0, only_matching_last); |
| if (only_matching == NULL) only_matching = only_matching_last; |
| break; |
| |
case 'q': quiet = TRUE; break; |
case 'q': quiet = TRUE; break; |
case 'r': dee_action = dee_RECURSE; break; |
case 'r': dee_action = dee_RECURSE; break; |
case 's': silent = TRUE; break; |
case 's': silent = TRUE; break; |
Line 1939 switch(letter)
|
Line 2282 switch(letter)
|
case 'x': process_options |= PO_LINE_MATCH; break; |
case 'x': process_options |= PO_LINE_MATCH; break; |
|
|
case 'V': |
case 'V': |
fprintf(stderr, "pcregrep version %s\n", pcre_version()); | fprintf(stdout, "pcregrep version %s\n", pcre_version()); |
pcregrep_exit(0); |
pcregrep_exit(0); |
break; |
break; |
|
|
Line 1983 return buffer;
|
Line 2326 return buffer;
|
* Compile a single pattern * |
* Compile a single pattern * |
*************************************************/ |
*************************************************/ |
|
|
/* When the -F option has been used, this is called for each substring. | /* Do nothing if the pattern has already been compiled. This is the case for |
Otherwise it's called for each supplied pattern. | include/exclude patterns read from a file. |
|
|
|
When the -F option has been used, each "pattern" may be a list of strings, |
|
separated by line breaks. They will be matched literally. We split such a |
|
string and compile the first substring, inserting an additional block into the |
|
pattern chain. |
|
|
Arguments: |
Arguments: |
pattern the pattern string | p points to the pattern block |
options the PCRE options |
options the PCRE options |
filename the file name, or NULL for a command-line pattern | popts the processing popts the processing options |
| fromfile TRUE if the pattern was read from a file |
| fromtext file name or identifying text (e.g. "include") |
count 0 if this is the only command line pattern, or |
count 0 if this is the only command line pattern, or |
number of the command line pattern, or |
number of the command line pattern, or |
linenumber for a pattern from a file |
linenumber for a pattern from a file |
Line 1998 Returns: TRUE on success, FALSE after an error
|
Line 2348 Returns: TRUE on success, FALSE after an error
|
*/ |
*/ |
|
|
static BOOL |
static BOOL |
compile_single_pattern(char *pattern, int options, char *filename, int count) | compile_pattern(patstr *p, int options, int popts, int fromfile, |
| const char *fromtext, int count) |
{ |
{ |
char buffer[PATBUFSIZE]; |
char buffer[PATBUFSIZE]; |
const char *error; |
const char *error; |
|
char *ps = p->string; |
|
int patlen = strlen(ps); |
int errptr; |
int errptr; |
|
|
if (pattern_count >= MAX_PATTERN_COUNT) | if (p->compiled != NULL) return TRUE; |
{ | |
fprintf(stderr, "pcregrep: Too many %spatterns (max %d)\n", | |
(filename == NULL)? "command-line " : "", MAX_PATTERN_COUNT); | |
return FALSE; | |
} | |
|
|
sprintf(buffer, "%s%.*s%s", prefix[process_options], bufthird, pattern, | if ((popts & PO_FIXED_STRINGS) != 0) |
suffix[process_options]); | |
pattern_list[pattern_count] = | |
pcre_compile(buffer, options, &error, &errptr, pcretables); | |
if (pattern_list[pattern_count] != NULL) | |
{ |
{ |
pattern_count++; | int ellength; |
return TRUE; | char *eop = ps + patlen; |
| char *pe = end_of_line(ps, eop, &ellength); |
| |
| if (ellength != 0) |
| { |
| if (add_pattern(pe, p) == NULL) return FALSE; |
| patlen = (int)(pe - ps - ellength); |
| } |
} |
} |
|
|
|
sprintf(buffer, "%s%.*s%s", prefix[popts], patlen, ps, suffix[popts]); |
|
p->compiled = pcre_compile(buffer, options, &error, &errptr, pcretables); |
|
if (p->compiled != NULL) return TRUE; |
|
|
/* Handle compile errors */ |
/* Handle compile errors */ |
|
|
errptr -= (int)strlen(prefix[process_options]); | errptr -= (int)strlen(prefix[popts]); |
if (errptr > (int)strlen(pattern)) errptr = (int)strlen(pattern); | if (errptr > patlen) errptr = patlen; |
|
|
if (filename == NULL) | if (fromfile) |
{ |
{ |
if (count == 0) | fprintf(stderr, "pcregrep: Error in regex in line %d of %s " |
fprintf(stderr, "pcregrep: Error in command-line regex " | "at offset %d: %s\n", count, fromtext, errptr, error); |
"at offset %d: %s\n", errptr, error); | |
else | |
fprintf(stderr, "pcregrep: Error in %s command-line regex " | |
"at offset %d: %s\n", ordin(count), errptr, error); | |
} |
} |
else |
else |
{ |
{ |
fprintf(stderr, "pcregrep: Error in regex in line %d of %s " | if (count == 0) |
"at offset %d: %s\n", count, filename, errptr, error); | fprintf(stderr, "pcregrep: Error in %s regex at offset %d: %s\n", |
| fromtext, errptr, error); |
| else |
| fprintf(stderr, "pcregrep: Error in %s %s regex at offset %d: %s\n", |
| ordin(count), fromtext, errptr, error); |
} |
} |
|
|
return FALSE; |
return FALSE; |
Line 2047 return FALSE;
|
Line 2402 return FALSE;
|
|
|
|
|
/************************************************* |
/************************************************* |
* Compile one supplied pattern * | * Read and compile a file of patterns * |
*************************************************/ |
*************************************************/ |
|
|
/* When the -F option has been used, each string may be a list of strings, | /* This is used for --filelist, --include-from, and --exclude-from. |
separated by line breaks. They will be matched literally. | |
|
|
Arguments: |
Arguments: |
pattern the pattern string | name the name of the file; "-" is stdin |
options the PCRE options | patptr pointer to the pattern chain anchor |
filename the file name, or NULL for a command-line pattern | patlastptr pointer to the last pattern pointer |
count 0 if this is the only command line pattern, or | popts the process options to pass to pattern_compile() |
number of the command line pattern, or | |
linenumber for a pattern from a file | |
|
|
Returns: TRUE on success, FALSE after an error | Returns: TRUE if all went well |
*/ |
*/ |
|
|
static BOOL |
static BOOL |
compile_pattern(char *pattern, int options, char *filename, int count) | read_pattern_file(char *name, patstr **patptr, patstr **patlastptr, int popts) |
{ |
{ |
if ((process_options & PO_FIXED_STRINGS) != 0) | int linenumber = 0; |
| FILE *f; |
| char *filename; |
| char buffer[PATBUFSIZE]; |
| |
| if (strcmp(name, "-") == 0) |
{ |
{ |
char *eop = pattern + strlen(pattern); | f = stdin; |
char buffer[PATBUFSIZE]; | filename = stdin_name; |
| } |
| else |
| { |
| f = fopen(name, "r"); |
| if (f == NULL) |
| { |
| fprintf(stderr, "pcregrep: Failed to open %s: %s\n", name, strerror(errno)); |
| return FALSE; |
| } |
| filename = name; |
| } |
| |
| while (fgets(buffer, PATBUFSIZE, f) != NULL) |
| { |
| char *s = buffer + (int)strlen(buffer); |
| while (s > buffer && isspace((unsigned char)(s[-1]))) s--; |
| *s = 0; |
| linenumber++; |
| if (buffer[0] == 0) continue; /* Skip blank lines */ |
| |
| /* Note: this call to add_pattern() puts a pointer to the local variable |
| "buffer" into the pattern chain. However, that pointer is used only when |
| compiling the pattern, which happens immediately below, so we flatten it |
| afterwards, as a precaution against any later code trying to use it. */ |
| |
| *patlastptr = add_pattern(buffer, *patlastptr); |
| if (*patlastptr == NULL) return FALSE; |
| if (*patptr == NULL) *patptr = *patlastptr; |
| |
| /* This loop is needed because compiling a "pattern" when -F is set may add |
| on additional literal patterns if the original contains a newline. In the |
| common case, it never will, because fgets() stops at a newline. However, |
| the -N option can be used to give pcregrep a different newline setting. */ |
| |
for(;;) |
for(;;) |
{ |
{ |
int ellength; | if (!compile_pattern(*patlastptr, pcre_options, popts, TRUE, filename, |
char *p = end_of_line(pattern, eop, &ellength); | linenumber)) |
if (ellength == 0) | |
return compile_single_pattern(pattern, options, filename, count); | |
sprintf(buffer, "%.*s", (int)(p - pattern - ellength), pattern); | |
pattern = p; | |
if (!compile_single_pattern(buffer, options, filename, count)) | |
return FALSE; |
return FALSE; |
|
(*patlastptr)->string = NULL; /* Insurance */ |
|
if ((*patlastptr)->next == NULL) break; |
|
*patlastptr = (*patlastptr)->next; |
} |
} |
} |
} |
else return compile_single_pattern(pattern, options, filename, count); | |
| if (f != stdin) fclose(f); |
| return TRUE; |
} |
} |
|
|
|
|
Line 2099 main(int argc, char **argv)
|
Line 2490 main(int argc, char **argv)
|
{ |
{ |
int i, j; |
int i, j; |
int rc = 1; |
int rc = 1; |
int pcre_options = 0; |
|
int cmd_pattern_count = 0; |
|
int hint_count = 0; |
|
int errptr; |
|
BOOL only_one_at_top; |
BOOL only_one_at_top; |
char *patterns[MAX_PATTERN_COUNT]; | patstr *cp; |
| fnstr *fn; |
const char *locale_from = "--locale"; |
const char *locale_from = "--locale"; |
const char *error; |
const char *error; |
|
|
Line 2144 for (i = 1; i < argc; i++)
|
Line 2532 for (i = 1; i < argc; i++)
|
|
|
if (argv[i][1] == 0) |
if (argv[i][1] == 0) |
{ |
{ |
if (pattern_filename != NULL || pattern_count > 0) break; | if (pattern_files != NULL || patterns != NULL) break; |
else pcregrep_exit(usage(2)); |
else pcregrep_exit(usage(2)); |
} |
} |
|
|
Line 2270 for (i = 1; i < argc; i++)
|
Line 2658 for (i = 1; i < argc; i++)
|
{ |
{ |
char *s = argv[i] + 1; |
char *s = argv[i] + 1; |
longop = FALSE; |
longop = FALSE; |
|
|
while (*s != 0) |
while (*s != 0) |
{ |
{ |
for (op = optionlist; op->one_char != 0; op++) |
for (op = optionlist; op->one_char != 0; op++) |
Line 2283 for (i = 1; i < argc; i++)
|
Line 2672 for (i = 1; i < argc; i++)
|
pcregrep_exit(usage(2)); |
pcregrep_exit(usage(2)); |
} |
} |
|
|
/* Check for a single-character option that has data: OP_OP_NUMBER | option_data = s+1; |
is used for one that either has a numerical number or defaults, i.e. the | |
data is optional. If a digit follows, there is data; if not, carry on | /* Break out if this is the last character in the string; it's handled |
| below like a single multi-char option. */ |
| |
| if (*option_data == 0) break; |
| |
| /* Check for a single-character option that has data: OP_OP_NUMBER(S) |
| are used for ones that either have a numerical number or defaults, i.e. |
| the data is optional. If a digit follows, there is data; if not, carry on |
with other single-character options in the same string. */ |
with other single-character options in the same string. */ |
|
|
option_data = s+1; | if (op->type == OP_OP_NUMBER || op->type == OP_OP_NUMBERS) |
if (op->type == OP_OP_NUMBER) | |
{ |
{ |
if (isdigit((unsigned char)s[1])) break; |
if (isdigit((unsigned char)s[1])) break; |
} |
} |
else /* Check for end or a dataless option */ | else /* Check for an option with data */ |
{ |
{ |
if (op->type != OP_NODATA || s[1] == 0) break; | if (op->type != OP_NODATA) break; |
} |
} |
|
|
/* Handle a single-character option with no data, then loop for the |
/* Handle a single-character option with no data, then loop for the |
Line 2315 for (i = 1; i < argc; i++)
|
Line 2710 for (i = 1; i < argc; i++)
|
continue; |
continue; |
} |
} |
|
|
/* If the option type is OP_OP_STRING or OP_OP_NUMBER, it's an option that | /* If the option type is OP_OP_STRING or OP_OP_NUMBER(S), it's an option that |
either has a value or defaults to something. It cannot have data in a |
either has a value or defaults to something. It cannot have data in a |
separate item. At the moment, the only such options are "colo(u)r", |
separate item. At the moment, the only such options are "colo(u)r", |
"only-matching", and Jeffrey Friedl's special -S debugging option. */ |
"only-matching", and Jeffrey Friedl's special -S debugging option. */ |
|
|
if (*option_data == 0 && |
if (*option_data == 0 && |
(op->type == OP_OP_STRING || op->type == OP_OP_NUMBER)) | (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER || |
| op->type == OP_OP_NUMBERS)) |
{ |
{ |
switch (op->one_char) |
switch (op->one_char) |
{ |
{ |
Line 2330 for (i = 1; i < argc; i++)
|
Line 2726 for (i = 1; i < argc; i++)
|
break; |
break; |
|
|
case 'o': |
case 'o': |
only_matching = 0; | only_matching_last = add_number(0, only_matching_last); |
| if (only_matching == NULL) only_matching = only_matching_last; |
break; |
break; |
|
|
#ifdef JFRIEDL_DEBUG |
#ifdef JFRIEDL_DEBUG |
Line 2354 for (i = 1; i < argc; i++)
|
Line 2751 for (i = 1; i < argc; i++)
|
option_data = argv[++i]; |
option_data = argv[++i]; |
} |
} |
|
|
/* If the option type is OP_PATLIST, it's the -e option, which can be called | /* If the option type is OP_OP_NUMBERS, the value is a number that is to be |
multiple times to create a list of patterns. */ | added to a chain of numbers. */ |
|
|
if (op->type == OP_PATLIST) | if (op->type == OP_OP_NUMBERS) |
{ |
{ |
if (cmd_pattern_count >= MAX_PATTERN_COUNT) | unsigned long int n = decode_number(option_data, op, longop); |
| omdatastr *omd = (omdatastr *)op->dataptr; |
| *(omd->lastptr) = add_number((int)n, *(omd->lastptr)); |
| if (*(omd->anchor) == NULL) *(omd->anchor) = *(omd->lastptr); |
| } |
| |
| /* If the option type is OP_PATLIST, it's the -e option, or one of the |
| include/exclude options, which can be called multiple times to create lists |
| of patterns. */ |
| |
| else if (op->type == OP_PATLIST) |
| { |
| patdatastr *pd = (patdatastr *)op->dataptr; |
| *(pd->lastptr) = add_pattern(option_data, *(pd->lastptr)); |
| if (*(pd->lastptr) == NULL) goto EXIT2; |
| if (*(pd->anchor) == NULL) *(pd->anchor) = *(pd->lastptr); |
| } |
| |
| /* If the option type is OP_FILELIST, it's one of the options that names a |
| file. */ |
| |
| else if (op->type == OP_FILELIST) |
| { |
| fndatastr *fd = (fndatastr *)op->dataptr; |
| fn = (fnstr *)malloc(sizeof(fnstr)); |
| if (fn == NULL) |
{ |
{ |
fprintf(stderr, "pcregrep: Too many command-line patterns (max %d)\n", | fprintf(stderr, "pcregrep: malloc failed\n"); |
MAX_PATTERN_COUNT); | goto EXIT2; |
return 2; | |
} |
} |
patterns[cmd_pattern_count++] = option_data; | fn->next = NULL; |
| fn->name = option_data; |
| if (*(fd->anchor) == NULL) |
| *(fd->anchor) = fn; |
| else |
| (*(fd->lastptr))->next = fn; |
| *(fd->lastptr) = fn; |
} |
} |
|
|
/* Handle OP_BINARY_FILES */ |
/* Handle OP_BINARY_FILES */ |
Line 2386 for (i = 1; i < argc; i++)
|
Line 2813 for (i = 1; i < argc; i++)
|
} |
} |
} |
} |
|
|
/* Otherwise, deal with single string or numeric data values. */ | /* Otherwise, deal with a single string or numeric data value. */ |
|
|
else if (op->type != OP_NUMBER && op->type != OP_LONGNUMBER && |
else if (op->type != OP_NUMBER && op->type != OP_LONGNUMBER && |
op->type != OP_OP_NUMBER) |
op->type != OP_OP_NUMBER) |
{ |
{ |
*((char **)op->dataptr) = option_data; |
*((char **)op->dataptr) = option_data; |
} |
} |
|
|
/* Avoid the use of strtoul() because SunOS4 doesn't have it. This is used |
|
only for unpicking arguments, so just keep it simple. */ |
|
|
|
else |
else |
{ |
{ |
unsigned long int n = 0; | unsigned long int n = decode_number(option_data, op, longop); |
char *endptr = option_data; | if (op->type == OP_LONGNUMBER) *((unsigned long int *)op->dataptr) = n; |
while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++; | else *((int *)op->dataptr) = n; |
while (isdigit((unsigned char)(*endptr))) | |
n = n * 10 + (int)(*endptr++ - '0'); | |
if (toupper(*endptr) == 'K') | |
{ | |
n *= 1024; | |
endptr++; | |
} | |
else if (toupper(*endptr) == 'M') | |
{ | |
n *= 1024*1024; | |
endptr++; | |
} | |
if (*endptr != 0) | |
{ | |
if (longop) | |
{ | |
char *equals = strchr(op->long_name, '='); | |
int nlen = (equals == NULL)? (int)strlen(op->long_name) : | |
(int)(equals - op->long_name); | |
fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n", | |
option_data, nlen, op->long_name); | |
} | |
else | |
fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n", | |
option_data, op->one_char); | |
pcregrep_exit(usage(2)); | |
} | |
if (op->type == OP_LONGNUMBER) | |
*((unsigned long int *)op->dataptr) = n; | |
else | |
*((int *)op->dataptr) = n; | |
} |
} |
} |
} |
|
|
Line 2446 if (both_context > 0)
|
Line 2838 if (both_context > 0)
|
} |
} |
|
|
/* Only one of --only-matching, --file-offsets, or --line-offsets is permitted. |
/* Only one of --only-matching, --file-offsets, or --line-offsets is permitted. |
However, the latter two set only_matching. */ | However, all three set show_only_matching because they display, each in their |
| own way, only the data that has matched. */ |
|
|
if ((only_matching >= 0 && (file_offsets || line_offsets)) || | if ((only_matching != NULL && (file_offsets || line_offsets)) || |
(file_offsets && line_offsets)) |
(file_offsets && line_offsets)) |
{ |
{ |
fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets " |
fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets " |
Line 2456 if ((only_matching >= 0 && (file_offsets || line_offse
|
Line 2849 if ((only_matching >= 0 && (file_offsets || line_offse
|
pcregrep_exit(usage(2)); |
pcregrep_exit(usage(2)); |
} |
} |
|
|
if (file_offsets || line_offsets) only_matching = 0; | if (only_matching != NULL || file_offsets || line_offsets) |
| show_only_matching = TRUE; |
|
|
/* If a locale has not been provided as an option, see if the LC_CTYPE or |
/* If a locale has not been provided as an option, see if the LC_CTYPE or |
LC_ALL environment variable is set, and if so, use it. */ |
LC_ALL environment variable is set, and if so, use it. */ |
Line 2580 if (jfriedl_XT != 0 || jfriedl_XR != 0)
|
Line 2974 if (jfriedl_XT != 0 || jfriedl_XR != 0)
|
} |
} |
#endif |
#endif |
|
|
/* Get memory for the main buffer, and to store the pattern and hints lists. */ | /* Get memory for the main buffer. */ |
|
|
bufsize = 3*bufthird; |
bufsize = 3*bufthird; |
main_buffer = (char *)malloc(bufsize); |
main_buffer = (char *)malloc(bufsize); |
pattern_list = (pcre **)malloc(MAX_PATTERN_COUNT * sizeof(pcre *)); |
|
hints_list = (pcre_extra **)malloc(MAX_PATTERN_COUNT * sizeof(pcre_extra *)); |
|
|
|
if (main_buffer == NULL || pattern_list == NULL || hints_list == NULL) | if (main_buffer == NULL) |
{ |
{ |
fprintf(stderr, "pcregrep: malloc failed\n"); |
fprintf(stderr, "pcregrep: malloc failed\n"); |
goto EXIT2; |
goto EXIT2; |
} |
} |
|
|
/* If no patterns were provided by -e, and there is no file provided by -f, | /* If no patterns were provided by -e, and there are no files provided by -f, |
the first argument is the one and only pattern, and it must exist. */ |
the first argument is the one and only pattern, and it must exist. */ |
|
|
if (cmd_pattern_count == 0 && pattern_filename == NULL) | if (patterns == NULL && pattern_files == NULL) |
{ |
{ |
if (i >= argc) return usage(2); |
if (i >= argc) return usage(2); |
patterns[cmd_pattern_count++] = argv[i++]; | patterns = patterns_last = add_pattern(argv[i++], NULL); |
| if (patterns == NULL) goto EXIT2; |
} |
} |
|
|
/* Compile the patterns that were provided on the command line, either by |
/* Compile the patterns that were provided on the command line, either by |
multiple uses of -e or as a single unkeyed pattern. */ | multiple uses of -e or as a single unkeyed pattern. We cannot do this until |
| after all the command-line options are read so that we know which PCRE options |
| to use. When -F is used, compile_pattern() may add another block into the |
| chain, so we must not access the next pointer till after the compile. */ |
|
|
for (j = 0; j < cmd_pattern_count; j++) | for (j = 1, cp = patterns; cp != NULL; j++, cp = cp->next) |
{ |
{ |
if (!compile_pattern(patterns[j], pcre_options, NULL, | if (!compile_pattern(cp, pcre_options, process_options, FALSE, "command-line", |
(j == 0 && cmd_pattern_count == 1)? 0 : j + 1)) | (j == 1 && patterns->next == NULL)? 0 : j)) |
goto EXIT2; |
goto EXIT2; |
} |
} |
|
|
/* Compile the regular expressions that are provided in a file. */ | /* Read and compile the regular expressions that are provided in files. */ |
|
|
if (pattern_filename != NULL) | for (fn = pattern_files; fn != NULL; fn = fn->next) |
{ |
{ |
int linenumber = 0; | if (!read_pattern_file(fn->name, &patterns, &patterns_last, process_options)) |
FILE *f; | goto EXIT2; |
char *filename; | } |
char buffer[PATBUFSIZE]; | |
|
|
if (strcmp(pattern_filename, "-") == 0) | /* Study the regular expressions, as we will be running them many times. If an |
{ | extra block is needed for a limit, set PCRE_STUDY_EXTRA_NEEDED so that one is |
f = stdin; | returned, even if studying produces no data. */ |
filename = stdin_name; | |
} | |
else | |
{ | |
f = fopen(pattern_filename, "r"); | |
if (f == NULL) | |
{ | |
fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pattern_filename, | |
strerror(errno)); | |
goto EXIT2; | |
} | |
filename = pattern_filename; | |
} | |
|
|
while (fgets(buffer, PATBUFSIZE, f) != NULL) | if (match_limit > 0 || match_limit_recursion > 0) |
{ | study_options |= PCRE_STUDY_EXTRA_NEEDED; |
char *s = buffer + (int)strlen(buffer); | |
while (s > buffer && isspace((unsigned char)(s[-1]))) s--; | |
*s = 0; | |
linenumber++; | |
if (buffer[0] == 0) continue; /* Skip blank lines */ | |
if (!compile_pattern(buffer, pcre_options, filename, linenumber)) | |
goto EXIT2; | |
} | |
|
|
if (f != stdin) fclose(f); | /* Unless JIT has been explicitly disabled, arrange a stack for it to use. */ |
} | |
|
|
/* Study the regular expressions, as we will be running them many times. Unless |
|
JIT has been explicitly disabled, arrange a stack for it to use. */ |
|
|
|
#ifdef SUPPORT_PCREGREP_JIT |
#ifdef SUPPORT_PCREGREP_JIT |
if ((study_options & PCRE_STUDY_JIT_COMPILE) != 0) |
if ((study_options & PCRE_STUDY_JIT_COMPILE) != 0) |
jit_stack = pcre_jit_stack_alloc(32*1024, 1024*1024); |
jit_stack = pcre_jit_stack_alloc(32*1024, 1024*1024); |
#endif |
#endif |
|
|
for (j = 0; j < pattern_count; j++) | for (j = 1, cp = patterns; cp != NULL; j++, cp = cp->next) |
{ |
{ |
hints_list[j] = pcre_study(pattern_list[j], study_options, &error); | cp->hint = pcre_study(cp->compiled, study_options, &error); |
if (error != NULL) |
if (error != NULL) |
{ |
{ |
char s[16]; |
char s[16]; |
if (pattern_count == 1) s[0] = 0; else sprintf(s, " number %d", j); | if (patterns->next == NULL) s[0] = 0; else sprintf(s, " number %d", j); |
fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error); |
fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error); |
goto EXIT2; |
goto EXIT2; |
} |
} |
hint_count++; |
|
#ifdef SUPPORT_PCREGREP_JIT |
#ifdef SUPPORT_PCREGREP_JIT |
if (jit_stack != NULL && hints_list[j] != NULL) | if (jit_stack != NULL && cp->hint != NULL) |
pcre_assign_jit_stack(hints_list[j], NULL, jit_stack); | pcre_assign_jit_stack(cp->hint, NULL, jit_stack); |
#endif |
#endif |
} |
} |
|
|
/* If --match-limit or --recursion-limit was set, put the value(s) into the |
/* If --match-limit or --recursion-limit was set, put the value(s) into the |
pcre_extra block for each pattern. */ | pcre_extra block for each pattern. There will always be an extra block because |
| of the use of PCRE_STUDY_EXTRA_NEEDED above. */ |
|
|
if (match_limit > 0 || match_limit_recursion > 0) | for (cp = patterns; cp != NULL; cp = cp->next) |
{ |
{ |
for (j = 0; j < pattern_count; j++) | if (match_limit > 0) |
{ |
{ |
if (hints_list[j] == NULL) | cp->hint->flags |= PCRE_EXTRA_MATCH_LIMIT; |
{ | cp->hint->match_limit = match_limit; |
hints_list[j] = malloc(sizeof(pcre_extra)); | |
if (hints_list[j] == NULL) | |
{ | |
fprintf(stderr, "pcregrep: malloc failed\n"); | |
pcregrep_exit(2); | |
} | |
} | |
if (match_limit > 0) | |
{ | |
hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT; | |
hints_list[j]->match_limit = match_limit; | |
} | |
if (match_limit_recursion > 0) | |
{ | |
hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; | |
hints_list[j]->match_limit_recursion = match_limit_recursion; | |
} | |
} |
} |
|
|
|
if (match_limit_recursion > 0) |
|
{ |
|
cp->hint->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; |
|
cp->hint->match_limit_recursion = match_limit_recursion; |
|
} |
} |
} |
|
|
/* If there are include or exclude patterns, compile them. */ | /* If there are include or exclude patterns read from the command line, compile |
| them. -F, -w, and -x do not apply, so the third argument of compile_pattern is |
| 0. */ |
|
|
if (exclude_pattern != NULL) | for (j = 0; j < 4; j++) |
{ |
{ |
exclude_compiled = pcre_compile(exclude_pattern, 0, &error, &errptr, | int k; |
pcretables); | for (k = 1, cp = *(incexlist[j]); cp != NULL; k++, cp = cp->next) |
if (exclude_compiled == NULL) | |
{ |
{ |
fprintf(stderr, "pcregrep: Error in 'exclude' regex at offset %d: %s\n", | if (!compile_pattern(cp, pcre_options, 0, FALSE, incexname[j], |
errptr, error); | (k == 1 && cp->next == NULL)? 0 : k)) |
goto EXIT2; | goto EXIT2; |
} |
} |
} |
} |
|
|
if (include_pattern != NULL) | /* Read and compile include/exclude patterns from files. */ |
| |
| for (fn = include_from; fn != NULL; fn = fn->next) |
{ |
{ |
include_compiled = pcre_compile(include_pattern, 0, &error, &errptr, | if (!read_pattern_file(fn->name, &include_patterns, &include_patterns_last, 0)) |
pcretables); | |
if (include_compiled == NULL) | |
{ | |
fprintf(stderr, "pcregrep: Error in 'include' regex at offset %d: %s\n", | |
errptr, error); | |
goto EXIT2; |
goto EXIT2; |
} |
|
} |
} |
|
|
if (exclude_dir_pattern != NULL) | for (fn = exclude_from; fn != NULL; fn = fn->next) |
{ |
{ |
exclude_dir_compiled = pcre_compile(exclude_dir_pattern, 0, &error, &errptr, | if (!read_pattern_file(fn->name, &exclude_patterns, &exclude_patterns_last, 0)) |
pcretables); | |
if (exclude_dir_compiled == NULL) | |
{ | |
fprintf(stderr, "pcregrep: Error in 'exclude_dir' regex at offset %d: %s\n", | |
errptr, error); | |
goto EXIT2; |
goto EXIT2; |
} |
|
} |
} |
|
|
if (include_dir_pattern != NULL) | /* If there are no files that contain lists of files to search, and there are |
| no file arguments, search stdin, and then exit. */ |
| |
| if (file_lists == NULL && i >= argc) |
{ |
{ |
include_dir_compiled = pcre_compile(include_dir_pattern, 0, &error, &errptr, | rc = pcregrep(stdin, FR_PLAIN, stdin_name, |
pcretables); | (filenames > FN_DEFAULT)? stdin_name : NULL); |
if (include_dir_compiled == NULL) | goto EXIT; |
{ | |
fprintf(stderr, "pcregrep: Error in 'include_dir' regex at offset %d: %s\n", | |
errptr, error); | |
goto EXIT2; | |
} | |
} |
} |
|
|
/* If a file that contains a list of files to search has been specified, read | /* If any files that contains a list of files to search have been specified, |
it line by line and search the given files. Otherwise, if there are no further | read them line by line and search the given files. */ |
arguments, do the business on stdin and exit. */ | |
|
|
if (file_list != NULL) | for (fn = file_lists; fn != NULL; fn = fn->next) |
{ |
{ |
char buffer[PATBUFSIZE]; |
char buffer[PATBUFSIZE]; |
FILE *fl; |
FILE *fl; |
if (strcmp(file_list, "-") == 0) fl = stdin; else | if (strcmp(fn->name, "-") == 0) fl = stdin; else |
{ |
{ |
fl = fopen(file_list, "rb"); | fl = fopen(fn->name, "rb"); |
if (fl == NULL) |
if (fl == NULL) |
{ |
{ |
fprintf(stderr, "pcregrep: Failed to open %s: %s\n", file_list, | fprintf(stderr, "pcregrep: Failed to open %s: %s\n", fn->name, |
strerror(errno)); |
strerror(errno)); |
goto EXIT2; |
goto EXIT2; |
} |
} |
Line 2787 if (file_list != NULL)
|
Line 3134 if (file_list != NULL)
|
else if (frc == 0 && rc == 1) rc = 0; |
else if (frc == 0 && rc == 1) rc = 0; |
} |
} |
} |
} |
if (fl != stdin) fclose (fl); | if (fl != stdin) fclose(fl); |
} |
} |
|
|
/* Do this only if there was no file list (and no file arguments). */ | /* After handling file-list, work through remaining arguments. Pass in the fact |
| that there is only one argument at top level - this suppresses the file name if |
| the argument is not a directory and filenames are not otherwise forced. */ |
|
|
else if (i >= argc) | only_one_at_top = i == argc - 1 && file_lists == NULL; |
{ | |
rc = pcregrep(stdin, FR_PLAIN, stdin_name, | |
(filenames > FN_DEFAULT)? stdin_name : NULL); | |
goto EXIT; | |
} | |
|
|
/* After handling file-list or if there are remaining arguments, work through |
|
them as files or directories. Pass in the fact that there is only one argument |
|
at top level - this suppresses the file name if the argument is not a directory |
|
and filenames are not otherwise forced. */ |
|
|
|
only_one_at_top = i == argc - 1 && file_list == NULL; |
|
|
|
for (; i < argc; i++) |
for (; i < argc; i++) |
{ |
{ |
int frc = grep_or_recurse(argv[i], dee_action == dee_RECURSE, |
int frc = grep_or_recurse(argv[i], dee_action == dee_RECURSE, |
Line 2818 EXIT:
|
Line 3155 EXIT:
|
#ifdef SUPPORT_PCREGREP_JIT |
#ifdef SUPPORT_PCREGREP_JIT |
if (jit_stack != NULL) pcre_jit_stack_free(jit_stack); |
if (jit_stack != NULL) pcre_jit_stack_free(jit_stack); |
#endif |
#endif |
|
|
if (main_buffer != NULL) free(main_buffer); |
if (main_buffer != NULL) free(main_buffer); |
if (pattern_list != NULL) | |
| free_pattern_chain(patterns); |
| free_pattern_chain(include_patterns); |
| free_pattern_chain(include_dir_patterns); |
| free_pattern_chain(exclude_patterns); |
| free_pattern_chain(exclude_dir_patterns); |
| |
| free_file_chain(exclude_from); |
| free_file_chain(include_from); |
| free_file_chain(pattern_files); |
| free_file_chain(file_lists); |
| |
| while (only_matching != NULL) |
{ |
{ |
for (i = 0; i < pattern_count; i++) free(pattern_list[i]); | omstr *this = only_matching; |
free(pattern_list); | only_matching = this->next; |
| free(this); |
} |
} |
if (hints_list != NULL) | |
{ | |
for (i = 0; i < hint_count; i++) | |
{ | |
if (hints_list[i] != NULL) pcre_free_study(hints_list[i]); | |
} | |
free(hints_list); | |
} | |
pcregrep_exit(rc); |
pcregrep_exit(rc); |
|
|
EXIT2: |
EXIT2: |