3 |
*************************************************/ |
*************************************************/ |
4 |
|
|
5 |
/* This is a grep program that uses the PCRE regular expression library to do |
/* This is a grep program that uses the PCRE regular expression library to do |
6 |
its pattern matching. On a Unix system it can recurse into directories. */ |
its pattern matching. On a Unix or Win32 system it can recurse into |
7 |
|
directories. */ |
8 |
|
|
9 |
#include <ctype.h> |
#include <ctype.h> |
10 |
#include <stdio.h> |
#include <stdio.h> |
19 |
|
|
20 |
typedef int BOOL; |
typedef int BOOL; |
21 |
|
|
22 |
#define VERSION "2.0 01-Aug-2001" |
#define VERSION "3.0 14-Jan-2003" |
23 |
#define MAX_PATTERN_COUNT 100 |
#define MAX_PATTERN_COUNT 100 |
24 |
|
|
25 |
|
|
58 |
{ 'n', "line-number", "print line number with output lines" }, |
{ 'n', "line-number", "print line number with output lines" }, |
59 |
{ 'r', "recursive", "recursively scan sub-directories" }, |
{ 'r', "recursive", "recursively scan sub-directories" }, |
60 |
{ 's', "no-messages", "suppress error messages" }, |
{ 's', "no-messages", "suppress error messages" }, |
61 |
|
{ 'u', "utf-8", "use UTF-8 mode" }, |
62 |
{ 'V', "version", "print version information and exit" }, |
{ 'V', "version", "print version information and exit" }, |
63 |
{ 'v', "invert-match", "select non-matching lines" }, |
{ 'v', "invert-match", "select non-matching lines" }, |
64 |
{ 'x', "line-regex", "force PATTERN to match only whole lines" }, |
{ 'x', "line-regex", "force PATTERN to match only whole lines" }, |
72 |
*************************************************/ |
*************************************************/ |
73 |
|
|
74 |
/* These functions are defined so that they can be made system specific, |
/* These functions are defined so that they can be made system specific, |
75 |
although at present the only ones are for Unix, and for "no directory recursion |
although at present the only ones are for Unix, Win32, and for "no directory |
76 |
support". */ |
recursion support". */ |
77 |
|
|
78 |
|
|
79 |
/************* Directory scanning in Unix ***********/ |
/************* Directory scanning in Unix ***********/ |
120 |
} |
} |
121 |
|
|
122 |
|
|
123 |
#else |
/************* Directory scanning in Win32 ***********/ |
124 |
|
|
125 |
|
/* I (Philip Hazel) have no means of testing this code. It was contributed by |
126 |
|
Lionel Fourquaux. */ |
127 |
|
|
128 |
|
|
129 |
|
#elif HAVE_WIN32API |
130 |
|
|
131 |
|
#ifndef STRICT |
132 |
|
# define STRICT |
133 |
|
#endif |
134 |
|
#ifndef WIN32_LEAN_AND_MEAN |
135 |
|
# define WIN32_LEAN_AND_MEAN |
136 |
|
#endif |
137 |
|
#include <windows.h> |
138 |
|
|
139 |
|
typedef struct directory_type |
140 |
|
{ |
141 |
|
HANDLE handle; |
142 |
|
BOOL first; |
143 |
|
WIN32_FIND_DATA data; |
144 |
|
} directory_type; |
145 |
|
|
146 |
|
int |
147 |
|
isdirectory(char *filename) |
148 |
|
{ |
149 |
|
DWORD attr = GetFileAttributes(filename); |
150 |
|
if (attr == INVALID_FILE_ATTRIBUTES) |
151 |
|
return 0; |
152 |
|
return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) ? '/' : 0; |
153 |
|
} |
154 |
|
|
155 |
|
directory_type * |
156 |
|
opendirectory(char *filename) |
157 |
|
{ |
158 |
|
size_t len; |
159 |
|
char *pattern; |
160 |
|
directory_type *dir; |
161 |
|
DWORD err; |
162 |
|
len = strlen(filename); |
163 |
|
pattern = (char *) malloc(len + 3); |
164 |
|
dir = (directory_type *) malloc(sizeof(*dir)); |
165 |
|
if ((pattern == NULL) || (dir == NULL)) |
166 |
|
{ |
167 |
|
fprintf(stderr, "pcregrep: malloc failed\n"); |
168 |
|
exit(2); |
169 |
|
} |
170 |
|
memcpy(pattern, filename, len); |
171 |
|
memcpy(&(pattern[len]), "\\*", 3); |
172 |
|
dir->handle = FindFirstFile(pattern, &(dir->data)); |
173 |
|
if (dir->handle != INVALID_HANDLE_VALUE) |
174 |
|
{ |
175 |
|
free(pattern); |
176 |
|
dir->first = TRUE; |
177 |
|
return dir; |
178 |
|
} |
179 |
|
err = GetLastError(); |
180 |
|
free(pattern); |
181 |
|
free(dir); |
182 |
|
errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT; |
183 |
|
return NULL; |
184 |
|
} |
185 |
|
|
186 |
|
char * |
187 |
|
readdirectory(directory_type *dir) |
188 |
|
{ |
189 |
|
for (;;) |
190 |
|
{ |
191 |
|
if (!dir->first) |
192 |
|
{ |
193 |
|
if (!FindNextFile(dir->handle, &(dir->data))) |
194 |
|
return NULL; |
195 |
|
} |
196 |
|
else |
197 |
|
{ |
198 |
|
dir->first = FALSE; |
199 |
|
} |
200 |
|
if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0) |
201 |
|
return dir->data.cFileName; |
202 |
|
} |
203 |
|
#ifndef _MSC_VER |
204 |
|
return NULL; /* Keep compiler happy; never executed */ |
205 |
|
#endif |
206 |
|
} |
207 |
|
|
208 |
|
void |
209 |
|
closedirectory(directory_type *dir) |
210 |
|
{ |
211 |
|
FindClose(dir->handle); |
212 |
|
free(dir); |
213 |
|
} |
214 |
|
|
215 |
|
|
216 |
/************* Directory scanning when we can't do it ***********/ |
/************* Directory scanning when we can't do it ***********/ |
217 |
|
|
218 |
/* The type is void, and apart from isdirectory(), the functions do nothing. */ |
/* The type is void, and apart from isdirectory(), the functions do nothing. */ |
219 |
|
|
220 |
|
#else |
221 |
|
|
222 |
typedef void directory_type; |
typedef void directory_type; |
223 |
|
|
224 |
int isdirectory(char *filename) { return FALSE; } |
int isdirectory(char *filename) { return FALSE; } |
356 |
} |
} |
357 |
|
|
358 |
/* If the file is not a directory, or we are not recursing, scan it. If this is |
/* If the file is not a directory, or we are not recursing, scan it. If this is |
359 |
the first and only argument at top level, we don't show the file name. |
the first and only argument at top level, we don't show the file name (unless |
360 |
Otherwise, control is via the show_filenames variable. */ |
we are only showing the file name). Otherwise, control is via the |
361 |
|
show_filenames variable. */ |
362 |
|
|
363 |
in = fopen(filename, "r"); |
in = fopen(filename, "r"); |
364 |
if (in == NULL) |
if (in == NULL) |
367 |
return 2; |
return 2; |
368 |
} |
} |
369 |
|
|
370 |
rc = pcregrep(in, (show_filenames && !only_one_at_top)? filename : NULL); |
rc = pcregrep(in, (filenames_only || (show_filenames && !only_one_at_top))? |
371 |
|
filename : NULL); |
372 |
fclose(in); |
fclose(in); |
373 |
return rc; |
return rc; |
374 |
} |
} |
383 |
static int |
static int |
384 |
usage(int rc) |
usage(int rc) |
385 |
{ |
{ |
386 |
fprintf(stderr, "Usage: pcregrep [-Vcfhilnrsvx] [long-options] pattern [file] ...\n"); |
fprintf(stderr, "Usage: pcregrep [-Vcfhilnrsvx] [long-options] [pattern] [file1 file2 ...]\n"); |
387 |
fprintf(stderr, "Type `pcregrep --help' for more information.\n"); |
fprintf(stderr, "Type `pcregrep --help' for more information.\n"); |
388 |
return rc; |
return rc; |
389 |
} |
} |
400 |
{ |
{ |
401 |
option_item *op; |
option_item *op; |
402 |
|
|
403 |
printf("Usage: pcregrep [OPTION]... PATTERN [FILE] ...\n"); |
printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n"); |
404 |
printf("Search for PATTERN in each FILE or standard input.\n"); |
printf("Search for PATTERN in each FILE or standard input.\n"); |
405 |
|
printf("PATTERN must be present if -f is not used.\n"); |
406 |
printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n"); |
printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n"); |
407 |
|
|
408 |
printf("Options:\n"); |
printf("Options:\n"); |
447 |
case 'n': number = TRUE; break; |
case 'n': number = TRUE; break; |
448 |
case 'r': recurse = TRUE; break; |
case 'r': recurse = TRUE; break; |
449 |
case 's': silent = TRUE; break; |
case 's': silent = TRUE; break; |
450 |
|
case 'u': options |= PCRE_UTF8; break; |
451 |
case 'v': invert = TRUE; break; |
case 'v': invert = TRUE; break; |
452 |
case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break; |
case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break; |
453 |
|
|
488 |
{ |
{ |
489 |
if (argv[i][0] != '-') break; |
if (argv[i][0] != '-') break; |
490 |
|
|
491 |
|
/* Missing options */ |
492 |
|
|
493 |
|
if (argv[i][1] == 0) exit(usage(2)); |
494 |
|
|
495 |
/* Long name options */ |
/* Long name options */ |
496 |
|
|
497 |
if (argv[i][1] == '-') |
if (argv[i][1] == '-') |
594 |
|
|
595 |
else |
else |
596 |
{ |
{ |
597 |
if (i >= argc) return usage(0); |
if (i >= argc) return usage(2); |
598 |
pattern_list[0] = pcre_compile(argv[i++], options, &error, &errptr, NULL); |
pattern_list[0] = pcre_compile(argv[i++], options, &error, &errptr, NULL); |
599 |
if (pattern_list[0] == NULL) |
if (pattern_list[0] == NULL) |
600 |
{ |
{ |