pcregrep.cpp

Go to the documentation of this file.
00001 /*************************************************
00002 *               pcregrep program                 *
00003 *************************************************/
00004 
00005 /* This is a grep program that uses the PCRE regular expression library to do
00006 its pattern matching. On a Unix or Win32 system it can recurse into
00007 directories.
00008 
00009            Copyright (c) 1997-2007 University of Cambridge
00010 
00011 -----------------------------------------------------------------------------
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014 
00015     * Redistributions of source code must retain the above copyright notice,
00016       this list of conditions and the following disclaimer.
00017 
00018     * Redistributions in binary form must reproduce the above copyright
00019       notice, this list of conditions and the following disclaimer in the
00020       documentation and/or other materials provided with the distribution.
00021 
00022     * Neither the name of the University of Cambridge nor the names of its
00023       contributors may be used to endorse or promote products derived from
00024       this software without specific prior written permission.
00025 
00026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00027 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00029 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00030 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00031 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00032 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00035 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00036 POSSIBILITY OF SUCH DAMAGE.
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 /* Values for the "filenames" variable, which specifies options for file name
00074 output. The order is important; it is assumed that a file name is wanted for
00075 all values greater than FN_DEFAULT. */
00076 
00077 enum { FN_NONE, FN_DEFAULT, FN_ONLY, FN_NOMATCH_ONLY, FN_FORCE };
00078 
00079 /* Actions for the -d and -D options */
00080 
00081 enum { dee_READ, dee_SKIP, dee_RECURSE };
00082 enum { DEE_READ, DEE_SKIP };
00083 
00084 /* Actions for special processing options (flag bits) */
00085 
00086 #define PO_WORD_MATCH     0x0001
00087 #define PO_LINE_MATCH     0x0002
00088 #define PO_FIXED_STRINGS  0x0004
00089 
00090 /* Line ending types */
00091 
00092 enum { EL_LF, EL_CR, EL_CRLF, EL_ANY, EL_ANYCRLF };
00093 
00094 
00095 
00096 /*************************************************
00097 *               Global variables                 *
00098 *************************************************/
00099 
00100 /* Jeffrey Friedl has some debugging requirements that are not part of the
00101 regular code. */
00102 
00103 #ifdef JFRIEDL_DEBUG
00104 static int S_arg = -1;
00105 static unsigned int jfriedl_XR = 0; /* repeat regex attempt this many times */
00106 static unsigned int jfriedl_XT = 0; /* replicate text this many times */
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 /* Structure for options and list of them */
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 /* Options without a single-letter equivalent get a negative value. This can be
00168 used to identify them. */
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 /* Tables for prefixing and suffixing patterns, according to the -w, -x, and -F
00220 options. These set the 1, 2, and 4 bits in process_options, respectively. Note
00221 that the combination of -w and -x has the same effect as -x on its own, so we
00222 can treat them as the same. */
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 /* UTF-8 tables - used only when the newline setting is "any". */
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 *            OS-specific functions               *
00244 *************************************************/
00245 
00246 /* These functions are defined so that they can be made system specific,
00247 although at present the only ones are for Unix, Win32, and for "no support". */
00248 
00249 
00250 /************* Directory scanning in Unix ***********/
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;        /* In the expectation that opening as a file will fail */
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 /* Control never reaches here */
00285 }
00286 
00287 static void
00288 closedirectory(directory_type *dir)
00289 {
00290 closedir(dir);
00291 }
00292 
00293 
00294 /************* Test for regular file in Unix **********/
00295 
00296 static int
00297 isregfile(char *filename)
00298 {
00299 struct stat statbuf;
00300 if (stat(filename, &statbuf) < 0)
00301   return 1;        /* In the expectation that opening as a file will fail */
00302 return (statbuf.st_mode & S_IFMT) == S_IFREG;
00303 }
00304 
00305 
00306 /************* Test stdout for being a terminal in Unix **********/
00307 
00308 static BOOL
00309 is_stdout_tty(void)
00310 {
00311 return isatty(fileno(stdout));
00312 }
00313 
00314 
00315 /************* Directory scanning in Win32 ***********/
00316 
00317 /* I (Philip Hazel) have no means of testing this code. It was contributed by
00318 Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES
00319 when it did not exist. */
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;   /* Keep compiler happy; never executed */
00402 #endif
00403 }
00404 
00405 void
00406 closedirectory(directory_type *dir)
00407 {
00408 FindClose(dir->handle);
00409 free(dir);
00410 }
00411 
00412 
00413 /************* Test for regular file in Win32 **********/
00414 
00415 /* I don't know how to do this, or if it can be done; assume all paths are
00416 regular if they are not directories. */
00417 
00418 int isregfile(char *filename)
00419 {
00420 return !isdirectory(filename)
00421 }
00422 
00423 
00424 /************* Test stdout for being a terminal in Win32 **********/
00425 
00426 /* I don't know how to do this; assume never */
00427 
00428 static BOOL
00429 is_stdout_tty(void)
00430 {
00431 FALSE;
00432 }
00433 
00434 
00435 /************* Directory scanning when we can't do it ***********/
00436 
00437 /* The type is void, and apart from isdirectory(), the functions do nothing. */
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 /************* Test for regular when we can't do it **********/
00450 
00451 /* Assume all files are regular. */
00452 
00453 int isregfile(char *filename) { return 1; }
00454 
00455 
00456 /************* Test stdout for being a terminal when we can't do it **********/
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 *     Provide strerror() for non-ANSI libraries  *
00472 *************************************************/
00473 
00474 /* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror()
00475 in their libraries, but can provide the same facility by this simple
00476 alternative function. */
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 /* HAVE_STRERROR */
00488 
00489 
00490 
00491 /*************************************************
00492 *             Find end of line                   *
00493 *************************************************/
00494 
00495 /* The length of the endline sequence that is found is set via lenptr. This may
00496 be zero at the very end of the file if there is no line-ending sequence there.
00497 
00498 Arguments:
00499   p         current position in line
00500   endptr    end of available data
00501   lenptr    where to put the length of the eol sequence
00502 
00503 Returns:    pointer to the last byte of the line
00504 */
00505 
00506 static char *
00507 end_of_line(char *p, char *endptr, int *lenptr)
00508 {
00509 switch(endlinetype)
00510   {
00511   default:      /* Just in case */
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];  /* Number of additional bytes */
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:    /* LF */
00573       *lenptr = 1;
00574       return p;
00575 
00576       case 0x0d:    /* CR */
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     }   /* End of loop for ANYCRLF case */
00589 
00590   *lenptr = 0;  /* Must have hit the end */
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];  /* Number of additional bytes */
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:    /* LF */
00617       case 0x0b:    /* VT */
00618       case 0x0c:    /* FF */
00619       *lenptr = 1;
00620       return p;
00621 
00622       case 0x0d:    /* CR */
00623       if (p < endptr && *p == 0x0a)
00624         {
00625         *lenptr = 2;
00626         p++;
00627         }
00628       else *lenptr = 1;
00629       return p;
00630 
00631       case 0x85:    /* NEL */
00632       *lenptr = utf8? 2 : 1;
00633       return p;
00634 
00635       case 0x2028:  /* LS */
00636       case 0x2029:  /* PS */
00637       *lenptr = 3;
00638       return p;
00639 
00640       default:
00641       break;
00642       }
00643     }   /* End of loop for ANY case */
00644 
00645   *lenptr = 0;  /* Must have hit the end */
00646   return endptr;
00647   }     /* End of overall switch */
00648 }
00649 
00650 
00651 
00652 /*************************************************
00653 *         Find start of previous line            *
00654 *************************************************/
00655 
00656 /* This is called when looking back for before lines to print.
00657 
00658 Arguments:
00659   p         start of the subsequent line
00660   startptr  start of available data
00661 
00662 Returns:    pointer to the start of the previous line
00663 */
00664 
00665 static char *
00666 previous_line(char *p, char *startptr)
00667 {
00668 switch(endlinetype)
00669   {
00670   default:      /* Just in case */
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;   /* But control should never get here */
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];  /* Number of additional bytes */
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:    /* LF */
00723       case 0x0d:    /* CR */
00724       return p;
00725 
00726       default:
00727       break;
00728       }
00729 
00730     else switch (c)
00731       {
00732       case 0x0a:    /* LF */
00733       case 0x0b:    /* VT */
00734       case 0x0c:    /* FF */
00735       case 0x0d:    /* CR */
00736       case 0x85:    /* NEL */
00737       case 0x2028:  /* LS */
00738       case 0x2029:  /* PS */
00739       return p;
00740 
00741       default:
00742       break;
00743       }
00744 
00745     p = pp;  /* Back one character */
00746     }        /* End of loop for ANY case */
00747 
00748   return startptr;  /* Hit start of data */
00749   }     /* End of overall switch */
00750 }
00751 
00752 
00753 
00754 
00755 
00756 /*************************************************
00757 *       Print the previous "after" lines         *
00758 *************************************************/
00759 
00760 /* This is called if we are about to lose said lines because of buffer filling,
00761 and at the end of the file. The data in the line is written using fwrite() so
00762 that a binary zero does not terminate it.
00763 
00764 Arguments:
00765   lastmatchnumber   the number of the last matching line, plus one
00766   lastmatchrestart  where we restarted after the last match
00767   endptr            end of available data
00768   printname         filename for printing
00769 
00770 Returns:            nothing
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 *            Grep an individual file             *
00797 *************************************************/
00798 
00799 /* This is called from grep_or_recurse() below. It uses a buffer that is three
00800 times the value of MBUFTHIRD. The matching point is never allowed to stray into
00801 the top third of the buffer, thus keeping more of the file available for
00802 context printing or for multiline scanning. For large files, the pointer will
00803 be in the middle third most of the time, so the bottom third is available for
00804 "before" context printing.
00805 
00806 Arguments:
00807   in           the fopened FILE stream
00808   printname    the file name if it is to be printed for each match
00809                or NULL if the file name is not to be printed
00810                it cannot be NULL if filenames[_nomatch]_only is set
00811 
00812 Returns:       0 if there was at least one match
00813                1 otherwise (no matches)
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 /* Do the first read into the start of the buffer and set up the pointer to
00832 end of what we have. */
00833 
00834 bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);
00835 endptr = buffer + bufflength;
00836 
00837 /* Loop while the current pointer is not at the end of the file. For large
00838 files, endptr will be at the end of the buffer when we are in the middle of the
00839 file, but ptr will never get there, because as soon as it gets over 2/3 of the
00840 way, the buffer is shifted left and re-filled. */
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   /* At this point, ptr is at the start of a line. We need to find the length
00851   of the subject string to pass to pcre_exec(). In multiline mode, it is the
00852   length remainder of the data in the buffer. Otherwise, it is the length of
00853   the next line. After matching, we always advance by the length of the next
00854   line. In multiline mode the PCRE_FIRSTLINE option is used for compiling, so
00855   that any match is constrained to be in the first line. */
00856 
00857   t = end_of_line(t, endptr, &endlinelength);
00858   linelength = t - ptr - endlinelength;
00859   length = multiline? (size_t)(endptr - ptr) : linelength;
00860 
00861   /* Extra processing for Jeffrey Friedl's debugging. */
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   /* Run through all the patterns until one matches. Note that we don't include
00911   the final newline in the subject string. */
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);   /* In case binary zero included */
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;    /* No more matching; don't show the line again */
00938       break;
00939       }
00940     }
00941 
00942   /* If it's a match or a not-match (as required), do what's wanted. */
00943 
00944   if (match != invert)
00945     {
00946     BOOL hyphenprinted = FALSE;
00947 
00948     /* We've failed if we want a file that doesn't have any matches. */
00949 
00950     if (filenames == FN_NOMATCH_ONLY) return 1;
00951 
00952     /* Just count if just counting is wanted. */
00953 
00954     if (count_only) count++;
00955 
00956     /* If all we want is a file name, there is no need to scan any more lines
00957     in the file. */
00958 
00959     else if (filenames == FN_ONLY)
00960       {
00961       fprintf(stdout, "%s\n", printname);
00962       return 0;
00963       }
00964 
00965     /* Likewise, if all we want is a yes/no answer. */
00966 
00967     else if (quiet) return 0;
00968 
00969     /* The --only-matching option prints just the substring that matched, and
00970     does not pring any context. */
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     /* This is the default case when none of the above options is set. We print
00981     the matching lines(s), possibly preceded and/or followed by other lines of
00982     context. */
00983 
00984     else
00985       {
00986       /* See if there is a requirement to print some "after" lines from a
00987       previous match. We never print any overlaps. */
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         /* It is important to advance lastmatchrestart during this printing so
01002         that it interacts correctly with any "before" printing below. Print
01003         each line's data using fwrite() in case there are binary zeroes. */
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       /* If there were non-contiguous lines printed above, insert hyphens. */
01018 
01019       if (hyphenpending)
01020         {
01021         fprintf(stdout, "--\n");
01022         hyphenpending = FALSE;
01023         hyphenprinted = TRUE;
01024         }
01025 
01026       /* See if there is a requirement to print some "before" lines for this
01027       match. Again, don't print overlaps. */
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       /* Now print the matching line(s); ensure we set hyphenpending at the end
01057       of the file if any context lines are being output. */
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       /* In multiline mode, we want to print to the end of the line in which
01066       the end of the matched string is found, so we adjust linelength and the
01067       line number appropriately, but only when there actually was a match
01068       (invert not set). Because the PCRE_FIRSTLINE option is set, the start of
01069       the match will always be before the first newline sequence. */
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       /*** NOTE: Use only fwrite() to output the data line, so that binary
01090       zeroes are treated as just another data character. */
01091 
01092       /* This extra option, for Jeffrey Friedl's debugging requirements,
01093       replaces the matched string, or a specific captured string if it exists,
01094       with X. When this happens, colouring is ignored. */
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       /* We have to split the line(s) up if colouring. */
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     /* End of doing what has to be done for a match */
01122 
01123     rc = 0;    /* Had some success */
01124 
01125     /* Remember where the last match happened for after_context. We remember
01126     where we are about to restart, and that line's number. */
01127 
01128     lastmatchrestart = ptr + linelength + endlinelength;
01129     lastmatchnumber = linenumber + 1;
01130     }
01131 
01132   /* For a match in multiline inverted mode (which of course did not cause
01133   anything to be printed), we have to move on to the end of the match before
01134   proceeding. */
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   /* Advance to after the newline and increment the line number. */
01151 
01152   ptr += linelength + endlinelength;
01153   linenumber++;
01154 
01155   /* If we haven't yet reached the end of the file (the buffer is full), and
01156   the current point is in the top 1/3 of the buffer, slide the buffer down by
01157   1/3 and refill it. Before we do this, if some unprinted "after" lines are
01158   about to be lost, print them. */
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     /* Now do the shuffle */
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     /* Adjust any last match point */
01178 
01179     if (lastmatchnumber > 0) lastmatchrestart -= MBUFTHIRD;
01180     }
01181   }     /* Loop through the whole file */
01182 
01183 /* End of file; print final "after" lines if wanted; do_after_lines sets
01184 hyphenpending if it prints something. */
01185 
01186 if (!only_matching && !count_only)
01187   {
01188   do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
01189   hyphenpending |= endhyphenpending;
01190   }
01191 
01192 /* Print the file name if we are looking for those without matches and there
01193 were none. If we found a match, we won't have got this far. */
01194 
01195 if (filenames == FN_NOMATCH_ONLY)
01196   {
01197   fprintf(stdout, "%s\n", printname);
01198   return 0;
01199   }
01200 
01201 /* Print the match count if wanted */
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 *     Grep a file or recurse into a directory    *
01216 *************************************************/
01217 
01218 /* Given a path name, if it's a directory, scan all the files if we are
01219 recursing; if it's a file, grep it.
01220 
01221 Arguments:
01222   pathname          the path to investigate
01223   dir_recurse       TRUE if recursing is wanted (-r or -drecurse)
01224   only_one_at_top   TRUE if the path is the only one at toplevel
01225 
01226 Returns:   0 if there was at least one match
01227            1 if there were no matches
01228            2 there was some kind of error
01229 
01230 However, file opening failures are suppressed if "silent" is set.
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 /* If the file name is "-" we scan stdin */
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 /* If the file is a directory, skip if skipping or if we are recursing, scan
01251 each file within it, subject to any include or exclude patterns that were set.
01252 The scanning code is localized so it can be made system-specific. */
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 /* If the file is not a directory and not a regular file, skip it if that's
01296 been requested. */
01297 
01298 else if (!isregfile(pathname) && DEE_action == DEE_SKIP) return 1;
01299 
01300 /* Control reaches here if we have a regular file, or if we have a directory
01301 and recursion or skipping was not requested, or if we have anything else and
01302 skipping was not requested. The scan proceeds. If this is the first and only
01303 argument at top level, we don't show the file name, unless we are only showing
01304 the file name, or the filename was forced (-H). */
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 *                Usage function                  *
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 *                Help function                   *
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 *    Handle a single-letter, no data option      *
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 *          Construct printed ordinal             *
01431 *************************************************/
01432 
01433 /* This turns a number into "1st", "3rd", etc. */
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 *          Compile a single pattern              *
01456 *************************************************/
01457 
01458 /* When the -F option has been used, this is called for each substring.
01459 Otherwise it's called for each supplied pattern.
01460 
01461 Arguments:
01462   pattern        the pattern string
01463   options        the PCRE options
01464   filename       the file name, or NULL for a command-line pattern
01465   count          0 if this is the only command line pattern, or
01466                  number of the command line pattern, or
01467                  linenumber for a pattern from a file
01468 
01469 Returns:         TRUE on success, FALSE after an error
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 /* Handle compile errors */
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 *           Compile one supplied pattern         *
01523 *************************************************/
01524 
01525 /* When the -F option has been used, each string may be a list of strings,
01526 separated by line breaks. They will be matched literally.
01527 
01528 Arguments:
01529   pattern        the pattern string
01530   options        the PCRE options
01531   filename       the file name, or NULL for a command-line pattern
01532   count          0 if this is the only command line pattern, or
01533                  number of the command line pattern, or
01534                  linenumber for a pattern from a file
01535 
01536 Returns:         TRUE on success, FALSE after an error
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 *                Main program                    *
01565 *************************************************/
01566 
01567 /* Returns 0 if something matched, 1 if nothing matched, 2 after an error. */
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 /* Set the default line ending value from the default in the PCRE library;
01584 "lf", "cr", "crlf", and "any" are supported. Anything else is treated as "lf".
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 /* Process the options */
01598 
01599 for (i = 1; i < argc; i++)
01600   {
01601   option_item *op = NULL;
01602   char *option_data = (char *)"";    /* default to keep compiler happy */
01603   BOOL longop;
01604   BOOL longopwasequals = FALSE;
01605 
01606   if (argv[i][0] != '-') break;
01607 
01608   /* If we hit an argument that is just "-", it may be a reference to STDIN,
01609   but only if we have previously had -e or -f to define the patterns. */
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   /* Handle a long name option, or -- to terminate the options */
01618 
01619   if (argv[i][1] == '-')
01620     {
01621     char *arg = argv[i] + 2;
01622     char *argequals = strchr(arg, '=');
01623 
01624     if (*arg == 0)    /* -- terminates options */
01625       {
01626       i++;
01627       break;                /* out of the options-handling loop */
01628       }
01629 
01630     longop = TRUE;
01631 
01632     /* Some long options have data that follows after =, for example file=name.
01633     Some options have variations in the long name spelling: specifically, we
01634     allow "regexp" because GNU grep allows it, though I personally go along
01635     with Jeffrey Friedl and Larry Wall in preferring "regex" without the "p".
01636     These options are entered in the table as "regex(p)". No option is in both
01637     these categories, fortunately. */
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)     /* Not a (p) case */
01644         {
01645         if (equals == NULL)  /* Not thing=data case */
01646           {
01647           if (strcmp(arg, op->long_name) == 0) break;
01648           }
01649         else                 /* Special case xxx=data */
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                   /* Special case xxxx(p) */
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   /* Jeffrey Friedl's debugging harness uses these additional options which
01687   are not in the right form for putting in the option table because they use
01688   only one hyphen, yet are more than one character long. By putting them
01689   separately here, they will not get displayed as part of the help() output,
01690   but I don't think Jeffrey will care about that. */
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   /* One-char options; many that have no data may be in a single argument; we
01710   continue till we hit the last one or one that needs data. */
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   /* At this point we should have op pointing to a matched option. If the type
01736   is NO_DATA, it means that there is no data, and the option might set
01737   something in the PCRE options. */
01738 
01739   if (op->type == OP_NODATA)
01740     {
01741     pcre_options = handle_option(op->one_char, pcre_options);
01742     continue;
01743     }
01744 
01745   /* If the option type is OP_OP_STRING or OP_OP_NUMBER, it's an option that
01746   either has a value or defaults to something. It cannot have data in a
01747   separate item. At the moment, the only such options are "colo(u)r" and
01748   Jeffrey Friedl's special -S debugging option. */
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   /* Otherwise, find the data string for the option. */
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   /* If the option type is OP_PATLIST, it's the -e option, which can be called
01780   multiple times to create a list of patterns. */
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   /* Otherwise, deal with single string or numeric data values. */
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 /* Options have been decoded. If -C was used, its value is used as a default
01823 for -A and -B. */
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 /* If a locale has not been provided as an option, see if the LC_CTYPE or
01832 LC_ALL environment variable is set, and if so, use it. */
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 /* If a locale has been provided, set it, and generate the tables the PCRE
01847 needs. Otherwise, pcretables==NULL, which causes the use of default tables. */
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 /* Sort out colouring */
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 /* Interpret the newline type; the default settings are Unix-like. */
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 /* Interpret the text values for -d and -D */
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 /* Check the values for Jeffrey Friedl's debugging options. */
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 /* Get memory to store the pattern and hints lists. */
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 /* If no patterns were provided by -e, and there is no file provided by -f,
01965 the first argument is the one and only pattern, and it must exist. */
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 /* Compile the patterns that were provided on the command line, either by
01974 multiple uses of -e or as a single unkeyed pattern. */
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 /* Compile the regular expressions that are provided in a file. */
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;   /* Skip blank lines */
02016     if (!compile_pattern(buffer, pcre_options, filename, linenumber))
02017       goto EXIT2;
02018     }
02019 
02020   if (f != stdin) fclose(f);
02021   }
02022 
02023 /* Study the regular expressions, as we will be running them many times */
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 /* If there are include or exclude patterns, compile them. */
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 /* If there are no further arguments, do the business on stdin and exit. */
02065 
02066 if (i >= argc)
02067   {
02068   rc = pcregrep(stdin, (filenames > FN_DEFAULT)? stdin_name : NULL);
02069   goto EXIT;
02070   }
02071 
02072 /* Otherwise, work through the remaining arguments as files or directories.
02073 Pass in the fact that there is only one argument at top level - this suppresses
02074 the file name if the argument is not a directory and filenames are not
02075 otherwise forced. */
02076 
02077 only_one_at_top = i == argc - 1;   /* Catch initial value of i */
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 /* End of pcregrep */

Generated on Sun Oct 12 18:50:24 2008 for Tamarin by  doxygen 1.4.6