00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #ifdef HAVE_CONFIG_H
00041 #include <config.h>
00042 #endif
00043
00044 #include <ctype.h>
00045 #include <locale.h>
00046 #include <stdio.h>
00047 #include <string.h>
00048 #include <stdlib.h>
00049 #include <errno.h>
00050
00051 #include <sys/types.h>
00052 #include <sys/stat.h>
00053
00054 #ifdef HAVE_UNISTD_H
00055 #include <unistd.h>
00056 #endif
00057
00058 #include <pcre.h>
00059
00060 #define FALSE 0
00061 #define TRUE 1
00062
00063 typedef int BOOL;
00064
00065 #define MAX_PATTERN_COUNT 100
00066
00067 #if BUFSIZ > 8192
00068 #define MBUFTHIRD BUFSIZ
00069 #else
00070 #define MBUFTHIRD 8192
00071 #endif
00072
00073
00074
00075
00076
00077 enum { FN_NONE, FN_DEFAULT, FN_ONLY, FN_NOMATCH_ONLY, FN_FORCE };
00078
00079
00080
00081 enum { dee_READ, dee_SKIP, dee_RECURSE };
00082 enum { DEE_READ, DEE_SKIP };
00083
00084
00085
00086 #define PO_WORD_MATCH 0x0001
00087 #define PO_LINE_MATCH 0x0002
00088 #define PO_FIXED_STRINGS 0x0004
00089
00090
00091
00092 enum { EL_LF, EL_CR, EL_CRLF, EL_ANY, EL_ANYCRLF };
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 #ifdef JFRIEDL_DEBUG
00104 static int S_arg = -1;
00105 static unsigned int jfriedl_XR = 0;
00106 static unsigned int jfriedl_XT = 0;
00107 static const char *jfriedl_prefix = "";
00108 static const char *jfriedl_postfix = "";
00109 #endif
00110
00111 static int endlinetype;
00112
00113 static char *colour_string = (char *)"1;31";
00114 static char *colour_option = NULL;
00115 static char *dee_option = NULL;
00116 static char *DEE_option = NULL;
00117 static char *newline = NULL;
00118 static char *pattern_filename = NULL;
00119 static char *stdin_name = (char *)"(standard input)";
00120 static char *locale = NULL;
00121
00122 static const unsigned char *pcretables = NULL;
00123
00124 static int pattern_count = 0;
00125 static pcre **pattern_list = NULL;
00126 static pcre_extra **hints_list = NULL;
00127
00128 static char *include_pattern = NULL;
00129 static char *exclude_pattern = NULL;
00130
00131 static pcre *include_compiled = NULL;
00132 static pcre *exclude_compiled = NULL;
00133
00134 static int after_context = 0;
00135 static int before_context = 0;
00136 static int both_context = 0;
00137 static int dee_action = dee_READ;
00138 static int DEE_action = DEE_READ;
00139 static int error_count = 0;
00140 static int filenames = FN_DEFAULT;
00141 static int process_options = 0;
00142
00143 static BOOL count_only = FALSE;
00144 static BOOL do_colour = FALSE;
00145 static BOOL hyphenpending = FALSE;
00146 static BOOL invert = FALSE;
00147 static BOOL multiline = FALSE;
00148 static BOOL number = FALSE;
00149 static BOOL only_matching = FALSE;
00150 static BOOL quiet = FALSE;
00151 static BOOL silent = FALSE;
00152 static BOOL utf8 = FALSE;
00153
00154
00155
00156 enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_OP_NUMBER,
00157 OP_PATLIST };
00158
00159 typedef struct option_item {
00160 int type;
00161 int one_char;
00162 void *dataptr;
00163 const char *long_name;
00164 const char *help_text;
00165 } option_item;
00166
00167
00168
00169
00170 #define N_COLOUR (-1)
00171 #define N_EXCLUDE (-2)
00172 #define N_HELP (-3)
00173 #define N_INCLUDE (-4)
00174 #define N_LABEL (-5)
00175 #define N_LOCALE (-6)
00176 #define N_NULL (-7)
00177
00178 static option_item optionlist[] = {
00179 { OP_NODATA, N_NULL, NULL, "", " terminate options" },
00180 { OP_NODATA, N_HELP, NULL, "help", "display this help and exit" },
00181 { OP_NUMBER, 'A', &after_context, "after-context=number", "set number of following context lines" },
00182 { OP_NUMBER, 'B', &before_context, "before-context=number", "set number of prior context lines" },
00183 { OP_OP_STRING, N_COLOUR, &colour_option, "color=option", "matched text color option" },
00184 { OP_NUMBER, 'C', &both_context, "context=number", "set number of context lines, before & after" },
00185 { OP_NODATA, 'c', NULL, "count", "print only a count of matching lines per FILE" },
00186 { OP_OP_STRING, N_COLOUR, &colour_option, "colour=option", "matched text colour option" },
00187 { OP_STRING, 'D', &DEE_option, "devices=action","how to handle devices, FIFOs, and sockets" },
00188 { OP_STRING, 'd', &dee_option, "directories=action", "how to handle directories" },
00189 { OP_PATLIST, 'e', NULL, "regex(p)", "specify pattern (may be used more than once)" },
00190 { OP_NODATA, 'F', NULL, "fixed_strings", "patterns are sets of newline-separated strings" },
00191 { OP_STRING, 'f', &pattern_filename, "file=path", "read patterns from file" },
00192 { OP_NODATA, 'H', NULL, "with-filename", "force the prefixing filename on output" },
00193 { OP_NODATA, 'h', NULL, "no-filename", "suppress the prefixing filename on output" },
00194 { OP_NODATA, 'i', NULL, "ignore-case", "ignore case distinctions" },
00195 { OP_NODATA, 'l', NULL, "files-with-matches", "print only FILE names containing matches" },
00196 { OP_NODATA, 'L', NULL, "files-without-match","print only FILE names not containing matches" },
00197 { OP_STRING, N_LABEL, &stdin_name, "label=name", "set name for standard input" },
00198 { OP_STRING, N_LOCALE, &locale, "locale=locale", "use the named locale" },
00199 { OP_NODATA, 'M', NULL, "multiline", "run in multiline mode" },
00200 { OP_STRING, 'N', &newline, "newline=type", "specify newline type (CR, LF, CRLF, ANYCRLF or ANY)" },
00201 { OP_NODATA, 'n', NULL, "line-number", "print line number with output lines" },
00202 { OP_NODATA, 'o', NULL, "only-matching", "show only the part of the line that matched" },
00203 { OP_NODATA, 'q', NULL, "quiet", "suppress output, just set return code" },
00204 { OP_NODATA, 'r', NULL, "recursive", "recursively scan sub-directories" },
00205 { OP_STRING, N_EXCLUDE,&exclude_pattern, "exclude=pattern","exclude matching files when recursing" },
00206 { OP_STRING, N_INCLUDE,&include_pattern, "include=pattern","include matching files when recursing" },
00207 #ifdef JFRIEDL_DEBUG
00208 { OP_OP_NUMBER, 'S', &S_arg, "jeffS", "replace matched (sub)string with X" },
00209 #endif
00210 { OP_NODATA, 's', NULL, "no-messages", "suppress error messages" },
00211 { OP_NODATA, 'u', NULL, "utf-8", "use UTF-8 mode" },
00212 { OP_NODATA, 'V', NULL, "version", "print version information and exit" },
00213 { OP_NODATA, 'v', NULL, "invert-match", "select non-matching lines" },
00214 { OP_NODATA, 'w', NULL, "word-regex(p)", "force patterns to match only as words" },
00215 { OP_NODATA, 'x', NULL, "line-regex(p)", "force patterns to match only whole lines" },
00216 { OP_NODATA, 0, NULL, NULL, NULL }
00217 };
00218
00219
00220
00221
00222
00223
00224 static const char *prefix[] = {
00225 "", "\\b", "^(?:", "^(?:", "\\Q", "\\b\\Q", "^(?:\\Q", "^(?:\\Q" };
00226
00227 static const char *suffix[] = {
00228 "", "\\b", ")$", ")$", "\\E", "\\E\\b", "\\E)$", "\\E)$" };
00229
00230
00231
00232 const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
00233
00234 const char utf8_table4[] = {
00235 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00236 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
00237 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
00238 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 #if defined HAVE_SYS_STAT_H && defined HAVE_DIRENT_H && defined HAVE_SYS_TYPES_H
00253 #include <sys/types.h>
00254 #include <sys/stat.h>
00255 #include <dirent.h>
00256
00257 typedef DIR directory_type;
00258
00259 static int
00260 isdirectory(char *filename)
00261 {
00262 struct stat statbuf;
00263 if (stat(filename, &statbuf) < 0)
00264 return 0;
00265 return ((statbuf.st_mode & S_IFMT) == S_IFDIR)? '/' : 0;
00266 }
00267
00268 static directory_type *
00269 opendirectory(char *filename)
00270 {
00271 return opendir(filename);
00272 }
00273
00274 static char *
00275 readdirectory(directory_type *dir)
00276 {
00277 for (;;)
00278 {
00279 struct dirent *dent = readdir(dir);
00280 if (dent == NULL) return NULL;
00281 if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0)
00282 return dent->d_name;
00283 }
00284
00285 }
00286
00287 static void
00288 closedirectory(directory_type *dir)
00289 {
00290 closedir(dir);
00291 }
00292
00293
00294
00295
00296 static int
00297 isregfile(char *filename)
00298 {
00299 struct stat statbuf;
00300 if (stat(filename, &statbuf) < 0)
00301 return 1;
00302 return (statbuf.st_mode & S_IFMT) == S_IFREG;
00303 }
00304
00305
00306
00307
00308 static BOOL
00309 is_stdout_tty(void)
00310 {
00311 return isatty(fileno(stdout));
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 #elif HAVE_WINDOWS_H
00323
00324 #ifndef STRICT
00325 # define STRICT
00326 #endif
00327 #ifndef WIN32_LEAN_AND_MEAN
00328 # define WIN32_LEAN_AND_MEAN
00329 #endif
00330 #ifndef INVALID_FILE_ATTRIBUTES
00331 #define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
00332 #endif
00333
00334 #include <windows.h>
00335
00336 typedef struct directory_type
00337 {
00338 HANDLE handle;
00339 BOOL first;
00340 WIN32_FIND_DATA data;
00341 } directory_type;
00342
00343 int
00344 isdirectory(char *filename)
00345 {
00346 DWORD attr = GetFileAttributes(filename);
00347 if (attr == INVALID_FILE_ATTRIBUTES)
00348 return 0;
00349 return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) ? '/' : 0;
00350 }
00351
00352 directory_type *
00353 opendirectory(char *filename)
00354 {
00355 size_t len;
00356 char *pattern;
00357 directory_type *dir;
00358 DWORD err;
00359 len = strlen(filename);
00360 pattern = (char *) malloc(len + 3);
00361 dir = (directory_type *) malloc(sizeof(*dir));
00362 if ((pattern == NULL) || (dir == NULL))
00363 {
00364 fprintf(stderr, "pcregrep: malloc failed\n");
00365 exit(2);
00366 }
00367 memcpy(pattern, filename, len);
00368 memcpy(&(pattern[len]), "\\*", 3);
00369 dir->handle = FindFirstFile(pattern, &(dir->data));
00370 if (dir->handle != INVALID_HANDLE_VALUE)
00371 {
00372 free(pattern);
00373 dir->first = TRUE;
00374 return dir;
00375 }
00376 err = GetLastError();
00377 free(pattern);
00378 free(dir);
00379 errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT;
00380 return NULL;
00381 }
00382
00383 char *
00384 readdirectory(directory_type *dir)
00385 {
00386 for (;;)
00387 {
00388 if (!dir->first)
00389 {
00390 if (!FindNextFile(dir->handle, &(dir->data)))
00391 return NULL;
00392 }
00393 else
00394 {
00395 dir->first = FALSE;
00396 }
00397 if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0)
00398 return dir->data.cFileName;
00399 }
00400 #ifndef _MSC_VER
00401 return NULL;
00402 #endif
00403 }
00404
00405 void
00406 closedirectory(directory_type *dir)
00407 {
00408 FindClose(dir->handle);
00409 free(dir);
00410 }
00411
00412
00413
00414
00415
00416
00417
00418 int isregfile(char *filename)
00419 {
00420 return !isdirectory(filename)
00421 }
00422
00423
00424
00425
00426
00427
00428 static BOOL
00429 is_stdout_tty(void)
00430 {
00431 FALSE;
00432 }
00433
00434
00435
00436
00437
00438
00439 #else
00440
00441 typedef void directory_type;
00442
00443 int isdirectory(char *filename) { return 0; }
00444 directory_type * opendirectory(char *filename) { return (directory_type*)0;}
00445 char *readdirectory(directory_type *dir) { return (char*)0;}
00446 void closedirectory(directory_type *dir) {}
00447
00448
00449
00450
00451
00452
00453 int isregfile(char *filename) { return 1; }
00454
00455
00456
00457
00458 static BOOL
00459 is_stdout_tty(void)
00460 {
00461 return FALSE;
00462 }
00463
00464
00465 #endif
00466
00467
00468
00469 #ifndef HAVE_STRERROR
00470
00471
00472
00473
00474
00475
00476
00477
00478 extern int sys_nerr;
00479 extern char *sys_errlist[];
00480
00481 char *
00482 strerror(int n)
00483 {
00484 if (n < 0 || n >= sys_nerr) return "unknown error number";
00485 return sys_errlist[n];
00486 }
00487 #endif
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 static char *
00507 end_of_line(char *p, char *endptr, int *lenptr)
00508 {
00509 switch(endlinetype)
00510 {
00511 default:
00512 case EL_LF:
00513 while (p < endptr && *p != '\n') p++;
00514 if (p < endptr)
00515 {
00516 *lenptr = 1;
00517 return p + 1;
00518 }
00519 *lenptr = 0;
00520 return endptr;
00521
00522 case EL_CR:
00523 while (p < endptr && *p != '\r') p++;
00524 if (p < endptr)
00525 {
00526 *lenptr = 1;
00527 return p + 1;
00528 }
00529 *lenptr = 0;
00530 return endptr;
00531
00532 case EL_CRLF:
00533 for (;;)
00534 {
00535 while (p < endptr && *p != '\r') p++;
00536 if (++p >= endptr)
00537 {
00538 *lenptr = 0;
00539 return endptr;
00540 }
00541 if (*p == '\n')
00542 {
00543 *lenptr = 2;
00544 return p + 1;
00545 }
00546 }
00547 break;
00548
00549 case EL_ANYCRLF:
00550 while (p < endptr)
00551 {
00552 int extra = 0;
00553 register int c = *((unsigned char *)p);
00554
00555 if (utf8 && c >= 0xc0)
00556 {
00557 int gcii, gcss;
00558 extra = utf8_table4[c & 0x3f];
00559 gcss = 6*extra;
00560 c = (c & utf8_table3[extra]) << gcss;
00561 for (gcii = 1; gcii <= extra; gcii++)
00562 {
00563 gcss -= 6;
00564 c |= (p[gcii] & 0x3f) << gcss;
00565 }
00566 }
00567
00568 p += 1 + extra;
00569
00570 switch (c)
00571 {
00572 case 0x0a:
00573 *lenptr = 1;
00574 return p;
00575
00576 case 0x0d:
00577 if (p < endptr && *p == 0x0a)
00578 {
00579 *lenptr = 2;
00580 p++;
00581 }
00582 else *lenptr = 1;
00583 return p;
00584
00585 default:
00586 break;
00587 }
00588 }
00589
00590 *lenptr = 0;
00591 return endptr;
00592
00593 case EL_ANY:
00594 while (p < endptr)
00595 {
00596 int extra = 0;
00597 register int c = *((unsigned char *)p);
00598
00599 if (utf8 && c >= 0xc0)
00600 {
00601 int gcii, gcss;
00602 extra = utf8_table4[c & 0x3f];
00603 gcss = 6*extra;
00604 c = (c & utf8_table3[extra]) << gcss;
00605 for (gcii = 1; gcii <= extra; gcii++)
00606 {
00607 gcss -= 6;
00608 c |= (p[gcii] & 0x3f) << gcss;
00609 }
00610 }
00611
00612 p += 1 + extra;
00613
00614 switch (c)
00615 {
00616 case 0x0a:
00617 case 0x0b:
00618 case 0x0c:
00619 *lenptr = 1;
00620 return p;
00621
00622 case 0x0d:
00623 if (p < endptr && *p == 0x0a)
00624 {
00625 *lenptr = 2;
00626 p++;
00627 }
00628 else *lenptr = 1;
00629 return p;
00630
00631 case 0x85:
00632 *lenptr = utf8? 2 : 1;
00633 return p;
00634
00635 case 0x2028:
00636 case 0x2029:
00637 *lenptr = 3;
00638 return p;
00639
00640 default:
00641 break;
00642 }
00643 }
00644
00645 *lenptr = 0;
00646 return endptr;
00647 }
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 static char *
00666 previous_line(char *p, char *startptr)
00667 {
00668 switch(endlinetype)
00669 {
00670 default:
00671 case EL_LF:
00672 p--;
00673 while (p > startptr && p[-1] != '\n') p--;
00674 return p;
00675
00676 case EL_CR:
00677 p--;
00678 while (p > startptr && p[-1] != '\n') p--;
00679 return p;
00680
00681 case EL_CRLF:
00682 for (;;)
00683 {
00684 p -= 2;
00685 while (p > startptr && p[-1] != '\n') p--;
00686 if (p <= startptr + 1 || p[-2] == '\r') return p;
00687 }
00688 return p;
00689
00690 case EL_ANY:
00691 case EL_ANYCRLF:
00692 if (*(--p) == '\n' && p > startptr && p[-1] == '\r') p--;
00693 if (utf8) while ((*p & 0xc0) == 0x80) p--;
00694
00695 while (p > startptr)
00696 {
00697 register int c;
00698 char *pp = p - 1;
00699
00700 if (utf8)
00701 {
00702 int extra = 0;
00703 while ((*pp & 0xc0) == 0x80) pp--;
00704 c = *((unsigned char *)pp);
00705 if (c >= 0xc0)
00706 {
00707 int gcii, gcss;
00708 extra = utf8_table4[c & 0x3f];
00709 gcss = 6*extra;
00710 c = (c & utf8_table3[extra]) << gcss;
00711 for (gcii = 1; gcii <= extra; gcii++)
00712 {
00713 gcss -= 6;
00714 c |= (pp[gcii] & 0x3f) << gcss;
00715 }
00716 }
00717 }
00718 else c = *((unsigned char *)pp);
00719
00720 if (endlinetype == EL_ANYCRLF) switch (c)
00721 {
00722 case 0x0a:
00723 case 0x0d:
00724 return p;
00725
00726 default:
00727 break;
00728 }
00729
00730 else switch (c)
00731 {
00732 case 0x0a:
00733 case 0x0b:
00734 case 0x0c:
00735 case 0x0d:
00736 case 0x85:
00737 case 0x2028:
00738 case 0x2029:
00739 return p;
00740
00741 default:
00742 break;
00743 }
00744
00745 p = pp;
00746 }
00747
00748 return startptr;
00749 }
00750 }
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773 static void do_after_lines(int lastmatchnumber, char *lastmatchrestart,
00774 char *endptr, char *printname)
00775 {
00776 if (after_context > 0 && lastmatchnumber > 0)
00777 {
00778 int count = 0;
00779 while (lastmatchrestart < endptr && count++ < after_context)
00780 {
00781 int ellength;
00782 char *pp = lastmatchrestart;
00783 if (printname != NULL) fprintf(stdout, "%s-", printname);
00784 if (number) fprintf(stdout, "%d-", lastmatchnumber++);
00785 pp = end_of_line(pp, endptr, &ellength);
00786 fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
00787 lastmatchrestart = pp;
00788 }
00789 hyphenpending = TRUE;
00790 }
00791 }
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816 static int
00817 pcregrep(FILE *in, char *printname)
00818 {
00819 int rc = 1;
00820 int linenumber = 1;
00821 int lastmatchnumber = 0;
00822 int count = 0;
00823 int offsets[99];
00824 char *lastmatchrestart = NULL;
00825 char buffer[3*MBUFTHIRD];
00826 char *ptr = buffer;
00827 char *endptr;
00828 size_t bufflength;
00829 BOOL endhyphenpending = FALSE;
00830
00831
00832
00833
00834 bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);
00835 endptr = buffer + bufflength;
00836
00837
00838
00839
00840
00841
00842 while (ptr < endptr)
00843 {
00844 int i, endlinelength;
00845 int mrc = 0;
00846 BOOL match = FALSE;
00847 char *t = ptr;
00848 size_t length, linelength;
00849
00850
00851
00852
00853
00854
00855
00856
00857 t = end_of_line(t, endptr, &endlinelength);
00858 linelength = t - ptr - endlinelength;
00859 length = multiline? (size_t)(endptr - ptr) : linelength;
00860
00861
00862
00863 #ifdef JFRIEDL_DEBUG
00864 if (jfriedl_XT || jfriedl_XR)
00865 {
00866 #include <sys/time.h>
00867 #include <time.h>
00868 struct timeval start_time, end_time;
00869 struct timezone dummy;
00870
00871 if (jfriedl_XT)
00872 {
00873 unsigned long newlen = length * jfriedl_XT + strlen(jfriedl_prefix) + strlen(jfriedl_postfix);
00874 const char *orig = ptr;
00875 ptr = malloc(newlen + 1);
00876 if (!ptr) {
00877 printf("out of memory");
00878 exit(2);
00879 }
00880 endptr = ptr;
00881 strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);
00882 for (i = 0; i < jfriedl_XT; i++) {
00883 strncpy(endptr, orig, length);
00884 endptr += length;
00885 }
00886 strcpy(endptr, jfriedl_postfix); endptr += strlen(jfriedl_postfix);
00887 length = newlen;
00888 }
00889
00890 if (gettimeofday(&start_time, &dummy) != 0)
00891 perror("bad gettimeofday");
00892
00893
00894 for (i = 0; i < jfriedl_XR; i++)
00895 match = (pcre_exec(pattern_list[0], hints_list[0], ptr, length, 0, 0, offsets, 99) >= 0);
00896
00897 if (gettimeofday(&end_time, &dummy) != 0)
00898 perror("bad gettimeofday");
00899
00900 double delta = ((end_time.tv_sec + (end_time.tv_usec / 1000000.0))
00901 -
00902 (start_time.tv_sec + (start_time.tv_usec / 1000000.0)));
00903
00904 printf("%s TIMER[%.4f]\n", match ? "MATCH" : "FAIL", delta);
00905 return 0;
00906 }
00907 #endif
00908
00909
00910
00911
00912
00913 for (i = 0; i < pattern_count; i++)
00914 {
00915 mrc = pcre_exec(pattern_list[i], hints_list[i], ptr, length, 0, 0,
00916 offsets, 99);
00917 if (mrc >= 0) { match = TRUE; break; }
00918 if (mrc != PCRE_ERROR_NOMATCH)
00919 {
00920 fprintf(stderr, "pcregrep: pcre_exec() error %d while matching ", mrc);
00921 if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);
00922 fprintf(stderr, "this line:\n");
00923 fwrite(ptr, 1, linelength, stderr);
00924 fprintf(stderr, "\n");
00925 if (error_count == 0 &&
00926 (mrc == PCRE_ERROR_MATCHLIMIT || mrc == PCRE_ERROR_RECURSIONLIMIT))
00927 {
00928 fprintf(stderr, "pcregrep: error %d means that a resource limit "
00929 "was exceeded\n", mrc);
00930 fprintf(stderr, "pcregrep: check your regex for nested unlimited loops\n");
00931 }
00932 if (error_count++ > 20)
00933 {
00934 fprintf(stderr, "pcregrep: too many errors - abandoned\n");
00935 exit(2);
00936 }
00937 match = invert;
00938 break;
00939 }
00940 }
00941
00942
00943
00944 if (match != invert)
00945 {
00946 BOOL hyphenprinted = FALSE;
00947
00948
00949
00950 if (filenames == FN_NOMATCH_ONLY) return 1;
00951
00952
00953
00954 if (count_only) count++;
00955
00956
00957
00958
00959 else if (filenames == FN_ONLY)
00960 {
00961 fprintf(stdout, "%s\n", printname);
00962 return 0;
00963 }
00964
00965
00966
00967 else if (quiet) return 0;
00968
00969
00970
00971
00972 else if (only_matching)
00973 {
00974 if (printname != NULL) fprintf(stdout, "%s:", printname);
00975 if (number) fprintf(stdout, "%d:", linenumber);
00976 fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
00977 fprintf(stdout, "\n");
00978 }
00979
00980
00981
00982
00983
00984 else
00985 {
00986
00987
00988
00989 if (after_context > 0 && lastmatchnumber > 0)
00990 {
00991 int ellength;
00992 int linecount = 0;
00993 char *p = lastmatchrestart;
00994
00995 while (p < ptr && linecount < after_context)
00996 {
00997 p = end_of_line(p, ptr, &ellength);
00998 linecount++;
00999 }
01000
01001
01002
01003
01004
01005 while (lastmatchrestart < p)
01006 {
01007 char *pp = lastmatchrestart;
01008 if (printname != NULL) fprintf(stdout, "%s-", printname);
01009 if (number) fprintf(stdout, "%d-", lastmatchnumber++);
01010 pp = end_of_line(pp, endptr, &ellength);
01011 fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
01012 lastmatchrestart = pp;
01013 }
01014 if (lastmatchrestart != ptr) hyphenpending = TRUE;
01015 }
01016
01017
01018
01019 if (hyphenpending)
01020 {
01021 fprintf(stdout, "--\n");
01022 hyphenpending = FALSE;
01023 hyphenprinted = TRUE;
01024 }
01025
01026
01027
01028
01029 if (before_context > 0)
01030 {
01031 int linecount = 0;
01032 char *p = ptr;
01033
01034 while (p > buffer && (lastmatchnumber == 0 || p > lastmatchrestart) &&
01035 linecount < before_context)
01036 {
01037 linecount++;
01038 p = previous_line(p, buffer);
01039 }
01040
01041 if (lastmatchnumber > 0 && p > lastmatchrestart && !hyphenprinted)
01042 fprintf(stdout, "--\n");
01043
01044 while (p < ptr)
01045 {
01046 int ellength;
01047 char *pp = p;
01048 if (printname != NULL) fprintf(stdout, "%s-", printname);
01049 if (number) fprintf(stdout, "%d-", linenumber - linecount--);
01050 pp = end_of_line(pp, endptr, &ellength);
01051 fwrite(p, 1, pp - p, stdout);
01052 p = pp;
01053 }
01054 }
01055
01056
01057
01058
01059 if (after_context > 0 || before_context > 0)
01060 endhyphenpending = TRUE;
01061
01062 if (printname != NULL) fprintf(stdout, "%s:", printname);
01063 if (number) fprintf(stdout, "%d:", linenumber);
01064
01065
01066
01067
01068
01069
01070
01071 if (multiline)
01072 {
01073 int ellength;
01074 char *endmatch = ptr;
01075 if (!invert)
01076 {
01077 endmatch += offsets[1];
01078 t = ptr;
01079 while (t < endmatch)
01080 {
01081 t = end_of_line(t, endptr, &ellength);
01082 if (t <= endmatch) linenumber++; else break;
01083 }
01084 }
01085 endmatch = end_of_line(endmatch, endptr, &ellength);
01086 linelength = endmatch - ptr - ellength;
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096 #ifdef JFRIEDL_DEBUG
01097 if (S_arg >= 0 && S_arg < mrc)
01098 {
01099 int first = S_arg * 2;
01100 int last = first + 1;
01101 fwrite(ptr, 1, offsets[first], stdout);
01102 fprintf(stdout, "X");
01103 fwrite(ptr + offsets[last], 1, linelength - offsets[last], stdout);
01104 }
01105 else
01106 #endif
01107
01108
01109
01110 if (do_colour)
01111 {
01112 fwrite(ptr, 1, offsets[0], stdout);
01113 fprintf(stdout, "%c[%sm", 0x1b, colour_string);
01114 fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
01115 fprintf(stdout, "%c[00m", 0x1b);
01116 fwrite(ptr + offsets[1], 1, linelength - offsets[1], stdout);
01117 }
01118 else fwrite(ptr, 1, linelength + endlinelength, stdout);
01119 }
01120
01121
01122
01123 rc = 0;
01124
01125
01126
01127
01128 lastmatchrestart = ptr + linelength + endlinelength;
01129 lastmatchnumber = linenumber + 1;
01130 }
01131
01132
01133
01134
01135
01136 if (multiline && invert && match)
01137 {
01138 int ellength;
01139 char *endmatch = ptr + offsets[1];
01140 t = ptr;
01141 while (t < endmatch)
01142 {
01143 t = end_of_line(t, endptr, &ellength);
01144 if (t <= endmatch) linenumber++; else break;
01145 }
01146 endmatch = end_of_line(endmatch, endptr, &ellength);
01147 linelength = endmatch - ptr - ellength;
01148 }
01149
01150
01151
01152 ptr += linelength + endlinelength;
01153 linenumber++;
01154
01155
01156
01157
01158
01159
01160 if (bufflength >= sizeof(buffer) && ptr > buffer + 2*MBUFTHIRD)
01161 {
01162 if (after_context > 0 &&
01163 lastmatchnumber > 0 &&
01164 lastmatchrestart < buffer + MBUFTHIRD)
01165 {
01166 do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
01167 lastmatchnumber = 0;
01168 }
01169
01170
01171
01172 memmove(buffer, buffer + MBUFTHIRD, 2*MBUFTHIRD);
01173 ptr -= MBUFTHIRD;
01174 bufflength = 2*MBUFTHIRD + fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in);
01175 endptr = buffer + bufflength;
01176
01177
01178
01179 if (lastmatchnumber > 0) lastmatchrestart -= MBUFTHIRD;
01180 }
01181 }
01182
01183
01184
01185
01186 if (!only_matching && !count_only)
01187 {
01188 do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
01189 hyphenpending |= endhyphenpending;
01190 }
01191
01192
01193
01194
01195 if (filenames == FN_NOMATCH_ONLY)
01196 {
01197 fprintf(stdout, "%s\n", printname);
01198 return 0;
01199 }
01200
01201
01202
01203 if (count_only)
01204 {
01205 if (printname != NULL) fprintf(stdout, "%s:", printname);
01206 fprintf(stdout, "%d\n", count);
01207 }
01208
01209 return rc;
01210 }
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233 static int
01234 grep_or_recurse(char *pathname, BOOL dir_recurse, BOOL only_one_at_top)
01235 {
01236 int rc = 1;
01237 int sep;
01238 FILE *in;
01239
01240
01241
01242 if (strcmp(pathname, "-") == 0)
01243 {
01244 return pcregrep(stdin,
01245 (filenames > FN_DEFAULT || (filenames == FN_DEFAULT && !only_one_at_top))?
01246 stdin_name : NULL);
01247 }
01248
01249
01250
01251
01252
01253
01254 if ((sep = isdirectory(pathname)) != 0)
01255 {
01256 if (dee_action == dee_SKIP) return 1;
01257 if (dee_action == dee_RECURSE)
01258 {
01259 char buffer[1024];
01260 char *nextfile;
01261 directory_type *dir = opendirectory(pathname);
01262
01263 if (dir == NULL)
01264 {
01265 if (!silent)
01266 fprintf(stderr, "pcregrep: Failed to open directory %s: %s\n", pathname,
01267 strerror(errno));
01268 return 2;
01269 }
01270
01271 while ((nextfile = readdirectory(dir)) != NULL)
01272 {
01273 int frc, blen;
01274 sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);
01275 blen = strlen(buffer);
01276
01277 if (exclude_compiled != NULL &&
01278 pcre_exec(exclude_compiled, NULL, buffer, blen, 0, 0, NULL, 0) >= 0)
01279 continue;
01280
01281 if (include_compiled != NULL &&
01282 pcre_exec(include_compiled, NULL, buffer, blen, 0, 0, NULL, 0) < 0)
01283 continue;
01284
01285 frc = grep_or_recurse(buffer, dir_recurse, FALSE);
01286 if (frc > 1) rc = frc;
01287 else if (frc == 0 && rc == 1) rc = 0;
01288 }
01289
01290 closedirectory(dir);
01291 return rc;
01292 }
01293 }
01294
01295
01296
01297
01298 else if (!isregfile(pathname) && DEE_action == DEE_SKIP) return 1;
01299
01300
01301
01302
01303
01304
01305
01306 in = fopen(pathname, "r");
01307 if (in == NULL)
01308 {
01309 if (!silent)
01310 fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pathname,
01311 strerror(errno));
01312 return 2;
01313 }
01314
01315 rc = pcregrep(in, (filenames > FN_DEFAULT ||
01316 (filenames == FN_DEFAULT && !only_one_at_top))? pathname : NULL);
01317
01318 fclose(in);
01319 return rc;
01320 }
01321
01322
01323
01324
01325
01326
01327
01328
01329 static int
01330 usage(int rc)
01331 {
01332 option_item *op;
01333 fprintf(stderr, "Usage: pcregrep [-");
01334 for (op = optionlist; op->one_char != 0; op++)
01335 {
01336 if (op->one_char > 0) fprintf(stderr, "%c", op->one_char);
01337 }
01338 fprintf(stderr, "] [long options] [pattern] [files]\n");
01339 fprintf(stderr, "Type `pcregrep --help' for more information.\n");
01340 return rc;
01341 }
01342
01343
01344
01345
01346
01347
01348
01349
01350 static void
01351 help(void)
01352 {
01353 option_item *op;
01354
01355 printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n");
01356 printf("Search for PATTERN in each FILE or standard input.\n");
01357 printf("PATTERN must be present if neither -e nor -f is used.\n");
01358 printf("\"-\" can be used as a file name to mean STDIN.\n\n");
01359 printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n");
01360
01361 printf("Options:\n");
01362
01363 for (op = optionlist; op->one_char != 0; op++)
01364 {
01365 int n;
01366 char s[4];
01367 if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, " ");
01368 printf(" %s --%s%n", s, op->long_name, &n);
01369 n = 30 - n;
01370 if (n < 1) n = 1;
01371 printf("%.*s%s\n", n, " ", op->help_text);
01372 }
01373
01374 printf("\nWhen reading patterns from a file instead of using a command line option,\n");
01375 printf("trailing white space is removed and blank lines are ignored.\n");
01376 printf("There is a maximum of %d patterns.\n", MAX_PATTERN_COUNT);
01377
01378 printf("\nWith no FILEs, read standard input. If fewer than two FILEs given, assume -h.\n");
01379 printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble.\n");
01380 }
01381
01382
01383
01384
01385
01386
01387
01388
01389 static int
01390 handle_option(int letter, int options)
01391 {
01392 switch(letter)
01393 {
01394 case N_HELP: help(); exit(0);
01395 case 'c': count_only = TRUE; break;
01396 case 'F': process_options |= PO_FIXED_STRINGS; break;
01397 case 'H': filenames = FN_FORCE; break;
01398 case 'h': filenames = FN_NONE; break;
01399 case 'i': options |= PCRE_CASELESS; break;
01400 case 'l': filenames = FN_ONLY; break;
01401 case 'L': filenames = FN_NOMATCH_ONLY; break;
01402 case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;
01403 case 'n': number = TRUE; break;
01404 case 'o': only_matching = TRUE; break;
01405 case 'q': quiet = TRUE; break;
01406 case 'r': dee_action = dee_RECURSE; break;
01407 case 's': silent = TRUE; break;
01408 case 'u': options |= PCRE_UTF8; utf8 = TRUE; break;
01409 case 'v': invert = TRUE; break;
01410 case 'w': process_options |= PO_WORD_MATCH; break;
01411 case 'x': process_options |= PO_LINE_MATCH; break;
01412
01413 case 'V':
01414 fprintf(stderr, "pcregrep version %s\n", pcre_version());
01415 exit(0);
01416 break;
01417
01418 default:
01419 fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);
01420 exit(usage(2));
01421 }
01422
01423 return options;
01424 }
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435 static char *
01436 ordin(int n)
01437 {
01438 static char buffer[8];
01439 char *p = buffer;
01440 sprintf(p, "%d", n);
01441 while (*p != 0) p++;
01442 switch (n%10)
01443 {
01444 case 1: strcpy(p, "st"); break;
01445 case 2: strcpy(p, "nd"); break;
01446 case 3: strcpy(p, "rd"); break;
01447 default: strcpy(p, "th"); break;
01448 }
01449 return buffer;
01450 }
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472 static BOOL
01473 compile_single_pattern(char *pattern, int options, char *filename, int count)
01474 {
01475 char buffer[MBUFTHIRD + 16];
01476 const char *error;
01477 int errptr;
01478
01479 if (pattern_count >= MAX_PATTERN_COUNT)
01480 {
01481 fprintf(stderr, "pcregrep: Too many %spatterns (max %d)\n",
01482 (filename == NULL)? "command-line " : "", MAX_PATTERN_COUNT);
01483 return FALSE;
01484 }
01485
01486 sprintf(buffer, "%s%.*s%s", prefix[process_options], MBUFTHIRD, pattern,
01487 suffix[process_options]);
01488 pattern_list[pattern_count] =
01489 pcre_compile(buffer, options, &error, &errptr, pcretables);
01490 if (pattern_list[pattern_count] != NULL)
01491 {
01492 pattern_count++;
01493 return TRUE;
01494 }
01495
01496
01497
01498 errptr -= (int)strlen(prefix[process_options]);
01499 if (errptr > (int)strlen(pattern)) errptr = (int)strlen(pattern);
01500
01501 if (filename == NULL)
01502 {
01503 if (count == 0)
01504 fprintf(stderr, "pcregrep: Error in command-line regex "
01505 "at offset %d: %s\n", errptr, error);
01506 else
01507 fprintf(stderr, "pcregrep: Error in %s command-line regex "
01508 "at offset %d: %s\n", ordin(count), errptr, error);
01509 }
01510 else
01511 {
01512 fprintf(stderr, "pcregrep: Error in regex in line %d of %s "
01513 "at offset %d: %s\n", count, filename, errptr, error);
01514 }
01515
01516 return FALSE;
01517 }
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539 static BOOL
01540 compile_pattern(char *pattern, int options, char *filename, int count)
01541 {
01542 if ((process_options & PO_FIXED_STRINGS) != 0)
01543 {
01544 char *eop = pattern + strlen(pattern);
01545 char buffer[MBUFTHIRD];
01546 for(;;)
01547 {
01548 int ellength;
01549 char *p = end_of_line(pattern, eop, &ellength);
01550 if (ellength == 0)
01551 return compile_single_pattern(pattern, options, filename, count);
01552 sprintf(buffer, "%.*s", (int)(p - pattern - ellength), pattern);
01553 pattern = p;
01554 if (!compile_single_pattern(buffer, options, filename, count))
01555 return FALSE;
01556 }
01557 }
01558 else return compile_single_pattern(pattern, options, filename, count);
01559 }
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569 int
01570 main(int argc, char **argv)
01571 {
01572 int i, j;
01573 int rc = 1;
01574 int pcre_options = 0;
01575 int cmd_pattern_count = 0;
01576 int hint_count = 0;
01577 int errptr;
01578 BOOL only_one_at_top;
01579 char *patterns[MAX_PATTERN_COUNT];
01580 const char *locale_from = "--locale";
01581 const char *error;
01582
01583
01584
01585
01586
01587 (void)pcre_config(PCRE_CONFIG_NEWLINE, &i);
01588 switch(i)
01589 {
01590 default: newline = (char *)"lf"; break;
01591 case '\r': newline = (char *)"cr"; break;
01592 case ('\r' << 8) | '\n': newline = (char *)"crlf"; break;
01593 case -1: newline = (char *)"any"; break;
01594 case -2: newline = (char *)"anycrlf"; break;
01595 }
01596
01597
01598
01599 for (i = 1; i < argc; i++)
01600 {
01601 option_item *op = NULL;
01602 char *option_data = (char *)"";
01603 BOOL longop;
01604 BOOL longopwasequals = FALSE;
01605
01606 if (argv[i][0] != '-') break;
01607
01608
01609
01610
01611 if (argv[i][1] == 0)
01612 {
01613 if (pattern_filename != NULL || pattern_count > 0) break;
01614 else exit(usage(2));
01615 }
01616
01617
01618
01619 if (argv[i][1] == '-')
01620 {
01621 char *arg = argv[i] + 2;
01622 char *argequals = strchr(arg, '=');
01623
01624 if (*arg == 0)
01625 {
01626 i++;
01627 break;
01628 }
01629
01630 longop = TRUE;
01631
01632
01633
01634
01635
01636
01637
01638
01639 for (op = optionlist; op->one_char != 0; op++)
01640 {
01641 char *opbra = strchr(op->long_name, '(');
01642 char *equals = strchr(op->long_name, '=');
01643 if (opbra == NULL)
01644 {
01645 if (equals == NULL)
01646 {
01647 if (strcmp(arg, op->long_name) == 0) break;
01648 }
01649 else
01650 {
01651 int oplen = equals - op->long_name;
01652 int arglen = (argequals == NULL)? (int)strlen(arg) : argequals - arg;
01653 if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)
01654 {
01655 option_data = arg + arglen;
01656 if (*option_data == '=')
01657 {
01658 option_data++;
01659 longopwasequals = TRUE;
01660 }
01661 break;
01662 }
01663 }
01664 }
01665 else
01666 {
01667 char buff1[24];
01668 char buff2[24];
01669 int baselen = opbra - op->long_name;
01670 sprintf(buff1, "%.*s", baselen, op->long_name);
01671 sprintf(buff2, "%s%.*s", buff1,
01672 (int)strlen(op->long_name) - baselen - 2, opbra + 1);
01673 if (strcmp(arg, buff1) == 0 || strcmp(arg, buff2) == 0)
01674 break;
01675 }
01676 }
01677
01678 if (op->one_char == 0)
01679 {
01680 fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);
01681 exit(usage(2));
01682 }
01683 }
01684
01685
01686
01687
01688
01689
01690
01691
01692 #ifdef JFRIEDL_DEBUG
01693 else if (strcmp(argv[i], "-pre") == 0) {
01694 jfriedl_prefix = argv[++i];
01695 continue;
01696 } else if (strcmp(argv[i], "-post") == 0) {
01697 jfriedl_postfix = argv[++i];
01698 continue;
01699 } else if (strcmp(argv[i], "-XT") == 0) {
01700 sscanf(argv[++i], "%d", &jfriedl_XT);
01701 continue;
01702 } else if (strcmp(argv[i], "-XR") == 0) {
01703 sscanf(argv[++i], "%d", &jfriedl_XR);
01704 continue;
01705 }
01706 #endif
01707
01708
01709
01710
01711
01712 else
01713 {
01714 char *s = argv[i] + 1;
01715 longop = FALSE;
01716 while (*s != 0)
01717 {
01718 for (op = optionlist; op->one_char != 0; op++)
01719 { if (*s == op->one_char) break; }
01720 if (op->one_char == 0)
01721 {
01722 fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",
01723 *s, argv[i]);
01724 exit(usage(2));
01725 }
01726 if (op->type != OP_NODATA || s[1] == 0)
01727 {
01728 option_data = s+1;
01729 break;
01730 }
01731 pcre_options = handle_option(*s++, pcre_options);
01732 }
01733 }
01734
01735
01736
01737
01738
01739 if (op->type == OP_NODATA)
01740 {
01741 pcre_options = handle_option(op->one_char, pcre_options);
01742 continue;
01743 }
01744
01745
01746
01747
01748
01749
01750 if (*option_data == 0 &&
01751 (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))
01752 {
01753 switch (op->one_char)
01754 {
01755 case N_COLOUR:
01756 colour_option = (char *)"auto";
01757 break;
01758 #ifdef JFRIEDL_DEBUG
01759 case 'S':
01760 S_arg = 0;
01761 break;
01762 #endif
01763 }
01764 continue;
01765 }
01766
01767
01768
01769 if (*option_data == 0)
01770 {
01771 if (i >= argc - 1 || longopwasequals)
01772 {
01773 fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);
01774 exit(usage(2));
01775 }
01776 option_data = argv[++i];
01777 }
01778
01779
01780
01781
01782 if (op->type == OP_PATLIST)
01783 {
01784 if (cmd_pattern_count >= MAX_PATTERN_COUNT)
01785 {
01786 fprintf(stderr, "pcregrep: Too many command-line patterns (max %d)\n",
01787 MAX_PATTERN_COUNT);
01788 return 2;
01789 }
01790 patterns[cmd_pattern_count++] = option_data;
01791 }
01792
01793
01794
01795 else if (op->type != OP_NUMBER && op->type != OP_OP_NUMBER)
01796 {
01797 *((char **)op->dataptr) = option_data;
01798 }
01799 else
01800 {
01801 char *endptr;
01802 int n = strtoul(option_data, &endptr, 10);
01803 if (*endptr != 0)
01804 {
01805 if (longop)
01806 {
01807 char *equals = strchr(op->long_name, '=');
01808 int nlen = (equals == NULL)? (int)strlen(op->long_name) :
01809 equals - op->long_name;
01810 fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",
01811 option_data, nlen, op->long_name);
01812 }
01813 else
01814 fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",
01815 option_data, op->one_char);
01816 exit(usage(2));
01817 }
01818 *((int *)op->dataptr) = n;
01819 }
01820 }
01821
01822
01823
01824
01825 if (both_context > 0)
01826 {
01827 if (after_context == 0) after_context = both_context;
01828 if (before_context == 0) before_context = both_context;
01829 }
01830
01831
01832
01833
01834 if (locale == NULL)
01835 {
01836 locale = getenv("LC_ALL");
01837 locale_from = "LCC_ALL";
01838 }
01839
01840 if (locale == NULL)
01841 {
01842 locale = getenv("LC_CTYPE");
01843 locale_from = "LC_CTYPE";
01844 }
01845
01846
01847
01848
01849 if (locale != NULL)
01850 {
01851 if (setlocale(LC_CTYPE, locale) == NULL)
01852 {
01853 fprintf(stderr, "pcregrep: Failed to set locale %s (obtained from %s)\n",
01854 locale, locale_from);
01855 return 2;
01856 }
01857 pcretables = pcre_maketables();
01858 }
01859
01860
01861
01862 if (colour_option != NULL && strcmp(colour_option, "never") != 0)
01863 {
01864 if (strcmp(colour_option, "always") == 0) do_colour = TRUE;
01865 else if (strcmp(colour_option, "auto") == 0) do_colour = is_stdout_tty();
01866 else
01867 {
01868 fprintf(stderr, "pcregrep: Unknown colour setting \"%s\"\n",
01869 colour_option);
01870 return 2;
01871 }
01872 if (do_colour)
01873 {
01874 char *cs = getenv("PCREGREP_COLOUR");
01875 if (cs == NULL) cs = getenv("PCREGREP_COLOR");
01876 if (cs != NULL) colour_string = cs;
01877 }
01878 }
01879
01880
01881
01882 if (strcmp(newline, "cr") == 0 || strcmp(newline, "CR") == 0)
01883 {
01884 pcre_options |= PCRE_NEWLINE_CR;
01885 endlinetype = EL_CR;
01886 }
01887 else if (strcmp(newline, "lf") == 0 || strcmp(newline, "LF") == 0)
01888 {
01889 pcre_options |= PCRE_NEWLINE_LF;
01890 endlinetype = EL_LF;
01891 }
01892 else if (strcmp(newline, "crlf") == 0 || strcmp(newline, "CRLF") == 0)
01893 {
01894 pcre_options |= PCRE_NEWLINE_CRLF;
01895 endlinetype = EL_CRLF;
01896 }
01897 else if (strcmp(newline, "any") == 0 || strcmp(newline, "ANY") == 0)
01898 {
01899 pcre_options |= PCRE_NEWLINE_ANY;
01900 endlinetype = EL_ANY;
01901 }
01902 else if (strcmp(newline, "anycrlf") == 0 || strcmp(newline, "ANYCRLF") == 0)
01903 {
01904 pcre_options |= PCRE_NEWLINE_ANYCRLF;
01905 endlinetype = EL_ANYCRLF;
01906 }
01907 else
01908 {
01909 fprintf(stderr, "pcregrep: Invalid newline specifier \"%s\"\n", newline);
01910 return 2;
01911 }
01912
01913
01914
01915 if (dee_option != NULL)
01916 {
01917 if (strcmp(dee_option, "read") == 0) dee_action = dee_READ;
01918 else if (strcmp(dee_option, "recurse") == 0) dee_action = dee_RECURSE;
01919 else if (strcmp(dee_option, "skip") == 0) dee_action = dee_SKIP;
01920 else
01921 {
01922 fprintf(stderr, "pcregrep: Invalid value \"%s\" for -d\n", dee_option);
01923 return 2;
01924 }
01925 }
01926
01927 if (DEE_option != NULL)
01928 {
01929 if (strcmp(DEE_option, "read") == 0) DEE_action = DEE_READ;
01930 else if (strcmp(DEE_option, "skip") == 0) DEE_action = DEE_SKIP;
01931 else
01932 {
01933 fprintf(stderr, "pcregrep: Invalid value \"%s\" for -D\n", DEE_option);
01934 return 2;
01935 }
01936 }
01937
01938
01939
01940 #ifdef JFRIEDL_DEBUG
01941 if (S_arg > 9)
01942 {
01943 fprintf(stderr, "pcregrep: bad value for -S option\n");
01944 return 2;
01945 }
01946 if (jfriedl_XT != 0 || jfriedl_XR != 0)
01947 {
01948 if (jfriedl_XT == 0) jfriedl_XT = 1;
01949 if (jfriedl_XR == 0) jfriedl_XR = 1;
01950 }
01951 #endif
01952
01953
01954
01955 pattern_list = (pcre **)malloc(MAX_PATTERN_COUNT * sizeof(pcre *));
01956 hints_list = (pcre_extra **)malloc(MAX_PATTERN_COUNT * sizeof(pcre_extra *));
01957
01958 if (pattern_list == NULL || hints_list == NULL)
01959 {
01960 fprintf(stderr, "pcregrep: malloc failed\n");
01961 goto EXIT2;
01962 }
01963
01964
01965
01966
01967 if (cmd_pattern_count == 0 && pattern_filename == NULL)
01968 {
01969 if (i >= argc) return usage(2);
01970 patterns[cmd_pattern_count++] = argv[i++];
01971 }
01972
01973
01974
01975
01976 for (j = 0; j < cmd_pattern_count; j++)
01977 {
01978 if (!compile_pattern(patterns[j], pcre_options, NULL,
01979 (j == 0 && cmd_pattern_count == 1)? 0 : j + 1))
01980 goto EXIT2;
01981 }
01982
01983
01984
01985 if (pattern_filename != NULL)
01986 {
01987 int linenumber = 0;
01988 FILE *f;
01989 char *filename;
01990 char buffer[MBUFTHIRD];
01991
01992 if (strcmp(pattern_filename, "-") == 0)
01993 {
01994 f = stdin;
01995 filename = stdin_name;
01996 }
01997 else
01998 {
01999 f = fopen(pattern_filename, "r");
02000 if (f == NULL)
02001 {
02002 fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pattern_filename,
02003 strerror(errno));
02004 goto EXIT2;
02005 }
02006 filename = pattern_filename;
02007 }
02008
02009 while (fgets(buffer, MBUFTHIRD, f) != NULL)
02010 {
02011 char *s = buffer + (int)strlen(buffer);
02012 while (s > buffer && isspace((unsigned char)(s[-1]))) s--;
02013 *s = 0;
02014 linenumber++;
02015 if (buffer[0] == 0) continue;
02016 if (!compile_pattern(buffer, pcre_options, filename, linenumber))
02017 goto EXIT2;
02018 }
02019
02020 if (f != stdin) fclose(f);
02021 }
02022
02023
02024
02025 for (j = 0; j < pattern_count; j++)
02026 {
02027 hints_list[j] = pcre_study(pattern_list[j], 0, &error);
02028 if (error != NULL)
02029 {
02030 char s[16];
02031 if (pattern_count == 1) s[0] = 0; else sprintf(s, " number %d", j);
02032 fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error);
02033 goto EXIT2;
02034 }
02035 hint_count++;
02036 }
02037
02038
02039
02040 if (exclude_pattern != NULL)
02041 {
02042 exclude_compiled = pcre_compile(exclude_pattern, 0, &error, &errptr,
02043 pcretables);
02044 if (exclude_compiled == NULL)
02045 {
02046 fprintf(stderr, "pcregrep: Error in 'exclude' regex at offset %d: %s\n",
02047 errptr, error);
02048 goto EXIT2;
02049 }
02050 }
02051
02052 if (include_pattern != NULL)
02053 {
02054 include_compiled = pcre_compile(include_pattern, 0, &error, &errptr,
02055 pcretables);
02056 if (include_compiled == NULL)
02057 {
02058 fprintf(stderr, "pcregrep: Error in 'include' regex at offset %d: %s\n",
02059 errptr, error);
02060 goto EXIT2;
02061 }
02062 }
02063
02064
02065
02066 if (i >= argc)
02067 {
02068 rc = pcregrep(stdin, (filenames > FN_DEFAULT)? stdin_name : NULL);
02069 goto EXIT;
02070 }
02071
02072
02073
02074
02075
02076
02077 only_one_at_top = i == argc - 1;
02078
02079 for (; i < argc; i++)
02080 {
02081 int frc = grep_or_recurse(argv[i], dee_action == dee_RECURSE,
02082 only_one_at_top);
02083 if (frc > 1) rc = frc;
02084 else if (frc == 0 && rc == 1) rc = 0;
02085 }
02086
02087 EXIT:
02088 if (pattern_list != NULL)
02089 {
02090 for (i = 0; i < pattern_count; i++) free(pattern_list[i]);
02091 free(pattern_list);
02092 }
02093 if (hints_list != NULL)
02094 {
02095 for (i = 0; i < hint_count; i++) free(hints_list[i]);
02096 free(hints_list);
02097 }
02098 return rc;
02099
02100 EXIT2:
02101 rc = 2;
02102 goto EXIT;
02103 }
02104
02105