| 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 |
{ |
{ |