/[pcre]/code/trunk/pcregrep.c
ViewVC logotype

Diff of /code/trunk/pcregrep.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 137 by ph10, Thu Mar 29 13:56:00 2007 UTC revision 377 by ph10, Sun Mar 1 12:07:19 2009 UTC
# Line 6  Line 6 
6  its pattern matching. On a Unix or Win32 system it can recurse into  its pattern matching. On a Unix or Win32 system it can recurse into
7  directories.  directories.
8    
9             Copyright (c) 1997-2007 University of Cambridge             Copyright (c) 1997-2009 University of Cambridge
10    
11  -----------------------------------------------------------------------------  -----------------------------------------------------------------------------
12  Redistribution and use in source and binary forms, with or without  Redistribution and use in source and binary forms, with or without
# Line 38  POSSIBILITY OF SUCH DAMAGE. Line 38  POSSIBILITY OF SUCH DAMAGE.
38  */  */
39    
40  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
41  #  include <config.h>  #include "config.h"
42  #endif  #endif
43    
44  #include <ctype.h>  #include <ctype.h>
# Line 50  POSSIBILITY OF SUCH DAMAGE. Line 50  POSSIBILITY OF SUCH DAMAGE.
50    
51  #include <sys/types.h>  #include <sys/types.h>
52  #include <sys/stat.h>  #include <sys/stat.h>
53    
54  #ifdef HAVE_UNISTD_H  #ifdef HAVE_UNISTD_H
55  #  include <unistd.h>  #include <unistd.h>
56    #endif
57    
58    #ifdef SUPPORT_LIBZ
59    #include <zlib.h>
60  #endif  #endif
61    
62  #include <pcre.h>  #ifdef SUPPORT_LIBBZ2
63    #include <bzlib.h>
64    #endif
65    
66    #include "pcre.h"
67    
68  #define FALSE 0  #define FALSE 0
69  #define TRUE 1  #define TRUE 1
# Line 75  all values greater than FN_DEFAULT. */ Line 84  all values greater than FN_DEFAULT. */
84    
85  enum { FN_NONE, FN_DEFAULT, FN_ONLY, FN_NOMATCH_ONLY, FN_FORCE };  enum { FN_NONE, FN_DEFAULT, FN_ONLY, FN_NOMATCH_ONLY, FN_FORCE };
86    
87    /* File reading styles */
88    
89    enum { FR_PLAIN, FR_LIBZ, FR_LIBBZ2 };
90    
91  /* Actions for the -d and -D options */  /* Actions for the -d and -D options */
92    
93  enum { dee_READ, dee_SKIP, dee_RECURSE };  enum { dee_READ, dee_SKIP, dee_RECURSE };
# Line 88  enum { DEE_READ, DEE_SKIP }; Line 101  enum { DEE_READ, DEE_SKIP };
101    
102  /* Line ending types */  /* Line ending types */
103    
104  enum { EL_LF, EL_CR, EL_CRLF, EL_ANY };  enum { EL_LF, EL_CR, EL_CRLF, EL_ANY, EL_ANYCRLF };
105    
106    
107    
# Line 126  static pcre_extra **hints_list = NULL; Line 139  static pcre_extra **hints_list = NULL;
139    
140  static char *include_pattern = NULL;  static char *include_pattern = NULL;
141  static char *exclude_pattern = NULL;  static char *exclude_pattern = NULL;
142    static char *include_dir_pattern = NULL;
143    static char *exclude_dir_pattern = NULL;
144    
145  static pcre *include_compiled = NULL;  static pcre *include_compiled = NULL;
146  static pcre *exclude_compiled = NULL;  static pcre *exclude_compiled = NULL;
147    static pcre *include_dir_compiled = NULL;
148    static pcre *exclude_dir_compiled = NULL;
149    
150  static int after_context = 0;  static int after_context = 0;
151  static int before_context = 0;  static int before_context = 0;
# Line 141  static int process_options = 0; Line 158  static int process_options = 0;
158    
159  static BOOL count_only = FALSE;  static BOOL count_only = FALSE;
160  static BOOL do_colour = FALSE;  static BOOL do_colour = FALSE;
161    static BOOL file_offsets = FALSE;
162  static BOOL hyphenpending = FALSE;  static BOOL hyphenpending = FALSE;
163  static BOOL invert = FALSE;  static BOOL invert = FALSE;
164    static BOOL line_offsets = FALSE;
165  static BOOL multiline = FALSE;  static BOOL multiline = FALSE;
166  static BOOL number = FALSE;  static BOOL number = FALSE;
167  static BOOL only_matching = FALSE;  static BOOL only_matching = FALSE;
# Line 166  typedef struct option_item { Line 185  typedef struct option_item {
185  /* Options without a single-letter equivalent get a negative value. This can be  /* Options without a single-letter equivalent get a negative value. This can be
186  used to identify them. */  used to identify them. */
187    
188  #define N_COLOUR    (-1)  #define N_COLOUR       (-1)
189  #define N_EXCLUDE   (-2)  #define N_EXCLUDE      (-2)
190  #define N_HELP      (-3)  #define N_EXCLUDE_DIR  (-3)
191  #define N_INCLUDE   (-4)  #define N_HELP         (-4)
192  #define N_LABEL     (-5)  #define N_INCLUDE      (-5)
193  #define N_LOCALE    (-6)  #define N_INCLUDE_DIR  (-6)
194  #define N_NULL      (-7)  #define N_LABEL        (-7)
195    #define N_LOCALE       (-8)
196    #define N_NULL         (-9)
197    #define N_LOFFSETS     (-10)
198    #define N_FOFFSETS     (-11)
199    
200  static option_item optionlist[] = {  static option_item optionlist[] = {
201    { OP_NODATA,    N_NULL,   NULL,              "",              "  terminate options" },    { OP_NODATA,    N_NULL,   NULL,              "",              "  terminate options" },
# Line 188  static option_item optionlist[] = { Line 211  static option_item optionlist[] = {
211    { OP_PATLIST,   'e',      NULL,              "regex(p)",      "specify pattern (may be used more than once)" },    { OP_PATLIST,   'e',      NULL,              "regex(p)",      "specify pattern (may be used more than once)" },
212    { OP_NODATA,    'F',      NULL,              "fixed_strings", "patterns are sets of newline-separated strings" },    { OP_NODATA,    'F',      NULL,              "fixed_strings", "patterns are sets of newline-separated strings" },
213    { OP_STRING,    'f',      &pattern_filename, "file=path",     "read patterns from file" },    { OP_STRING,    'f',      &pattern_filename, "file=path",     "read patterns from file" },
214      { OP_NODATA,    N_FOFFSETS, NULL,            "file-offsets",  "output file offsets, not text" },
215    { OP_NODATA,    'H',      NULL,              "with-filename", "force the prefixing filename on output" },    { OP_NODATA,    'H',      NULL,              "with-filename", "force the prefixing filename on output" },
216    { OP_NODATA,    'h',      NULL,              "no-filename",   "suppress the prefixing filename on output" },    { OP_NODATA,    'h',      NULL,              "no-filename",   "suppress the prefixing filename on output" },
217    { OP_NODATA,    'i',      NULL,              "ignore-case",   "ignore case distinctions" },    { OP_NODATA,    'i',      NULL,              "ignore-case",   "ignore case distinctions" },
218    { OP_NODATA,    'l',      NULL,              "files-with-matches", "print only FILE names containing matches" },    { OP_NODATA,    'l',      NULL,              "files-with-matches", "print only FILE names containing matches" },
219    { OP_NODATA,    'L',      NULL,              "files-without-match","print only FILE names not containing matches" },    { OP_NODATA,    'L',      NULL,              "files-without-match","print only FILE names not containing matches" },
220    { OP_STRING,    N_LABEL,  &stdin_name,       "label=name",    "set name for standard input" },    { OP_STRING,    N_LABEL,  &stdin_name,       "label=name",    "set name for standard input" },
221      { OP_NODATA,    N_LOFFSETS, NULL,            "line-offsets",  "output line numbers and offsets, not text" },
222    { OP_STRING,    N_LOCALE, &locale,           "locale=locale", "use the named locale" },    { OP_STRING,    N_LOCALE, &locale,           "locale=locale", "use the named locale" },
223    { OP_NODATA,    'M',      NULL,              "multiline",     "run in multiline mode" },    { OP_NODATA,    'M',      NULL,              "multiline",     "run in multiline mode" },
224    { OP_STRING,    'N',      &newline,          "newline=type",  "specify newline type (CR, LR, CRLF)" },    { OP_STRING,    'N',      &newline,          "newline=type",  "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" },
225    { OP_NODATA,    'n',      NULL,              "line-number",   "print line number with output lines" },    { OP_NODATA,    'n',      NULL,              "line-number",   "print line number with output lines" },
226    { OP_NODATA,    'o',      NULL,              "only-matching", "show only the part of the line that matched" },    { OP_NODATA,    'o',      NULL,              "only-matching", "show only the part of the line that matched" },
227    { OP_NODATA,    'q',      NULL,              "quiet",         "suppress output, just set return code" },    { OP_NODATA,    'q',      NULL,              "quiet",         "suppress output, just set return code" },
228    { OP_NODATA,    'r',      NULL,              "recursive",     "recursively scan sub-directories" },    { OP_NODATA,    'r',      NULL,              "recursive",     "recursively scan sub-directories" },
229    { OP_STRING,    N_EXCLUDE,&exclude_pattern,  "exclude=pattern","exclude matching files when recursing" },    { OP_STRING,    N_EXCLUDE,&exclude_pattern,  "exclude=pattern","exclude matching files when recursing" },
230    { OP_STRING,    N_INCLUDE,&include_pattern,  "include=pattern","include matching files when recursing" },    { OP_STRING,    N_INCLUDE,&include_pattern,  "include=pattern","include matching files when recursing" },
231      { OP_STRING,    N_EXCLUDE_DIR,&exclude_dir_pattern, "exclude_dir=pattern","exclude matching directories when recursing" },
232      { OP_STRING,    N_INCLUDE_DIR,&include_dir_pattern, "include_dir=pattern","include matching directories when recursing" },
233  #ifdef JFRIEDL_DEBUG  #ifdef JFRIEDL_DEBUG
234    { OP_OP_NUMBER, 'S',      &S_arg,            "jeffS",         "replace matched (sub)string with X" },    { OP_OP_NUMBER, 'S',      &S_arg,            "jeffS",         "replace matched (sub)string with X" },
235  #endif  #endif
# Line 226  static const char *prefix[] = { Line 253  static const char *prefix[] = {
253  static const char *suffix[] = {  static const char *suffix[] = {
254    "", "\\b", ")$",   ")$",   "\\E", "\\E\\b", "\\E)$",   "\\E)$" };    "", "\\b", ")$",   ")$",   "\\E", "\\E\\b", "\\E)$",   "\\E)$" };
255    
256  /* UTF-8 tables - used only when the newline setting is "all". */  /* UTF-8 tables - used only when the newline setting is "any". */
257    
258  const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};  const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
259    
# Line 280  for (;;) Line 307  for (;;)
307    if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0)    if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0)
308      return dent->d_name;      return dent->d_name;
309    }    }
310  return NULL;   /* Keep compiler happy; never executed */  /* Control never reaches here */
311  }  }
312    
313  static void  static void
# Line 315  return isatty(fileno(stdout)); Line 342  return isatty(fileno(stdout));
342    
343  /* I (Philip Hazel) have no means of testing this code. It was contributed by  /* I (Philip Hazel) have no means of testing this code. It was contributed by
344  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES
345  when it did not exist. */  when it did not exist. David Byron added a patch that moved the #include of
346    <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.
347    */
348    
349  #elif HAVE_WINDOWS_H  #elif HAVE_WINDOWS_H
350    
# Line 326  when it did not exist. */ Line 354  when it did not exist. */
354  #ifndef WIN32_LEAN_AND_MEAN  #ifndef WIN32_LEAN_AND_MEAN
355  # define WIN32_LEAN_AND_MEAN  # define WIN32_LEAN_AND_MEAN
356  #endif  #endif
357    
358    #include <windows.h>
359    
360  #ifndef INVALID_FILE_ATTRIBUTES  #ifndef INVALID_FILE_ATTRIBUTES
361  #define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF  #define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
362  #endif  #endif
363    
 #include <windows.h>  
   
364  typedef struct directory_type  typedef struct directory_type
365  {  {
366  HANDLE handle;  HANDLE handle;
# Line 416  regular if they are not directories. */ Line 445  regular if they are not directories. */
445    
446  int isregfile(char *filename)  int isregfile(char *filename)
447  {  {
448  return !isdirectory(filename)  return !isdirectory(filename);
449  }  }
450    
451    
# Line 427  return !isdirectory(filename) Line 456  return !isdirectory(filename)
456  static BOOL  static BOOL
457  is_stdout_tty(void)  is_stdout_tty(void)
458  {  {
459  FALSE;  return FALSE;
460  }  }
461    
462    
# Line 545  switch(endlinetype) Line 574  switch(endlinetype)
574      }      }
575    break;    break;
576    
577      case EL_ANYCRLF:
578      while (p < endptr)
579        {
580        int extra = 0;
581        register int c = *((unsigned char *)p);
582    
583        if (utf8 && c >= 0xc0)
584          {
585          int gcii, gcss;
586          extra = utf8_table4[c & 0x3f];  /* Number of additional bytes */
587          gcss = 6*extra;
588          c = (c & utf8_table3[extra]) << gcss;
589          for (gcii = 1; gcii <= extra; gcii++)
590            {
591            gcss -= 6;
592            c |= (p[gcii] & 0x3f) << gcss;
593            }
594          }
595    
596        p += 1 + extra;
597    
598        switch (c)
599          {
600          case 0x0a:    /* LF */
601          *lenptr = 1;
602          return p;
603    
604          case 0x0d:    /* CR */
605          if (p < endptr && *p == 0x0a)
606            {
607            *lenptr = 2;
608            p++;
609            }
610          else *lenptr = 1;
611          return p;
612    
613          default:
614          break;
615          }
616        }   /* End of loop for ANYCRLF case */
617    
618      *lenptr = 0;  /* Must have hit the end */
619      return endptr;
620    
621    case EL_ANY:    case EL_ANY:
622    while (p < endptr)    while (p < endptr)
623      {      {
# Line 643  switch(endlinetype) Line 716  switch(endlinetype)
716    return p;   /* But control should never get here */    return p;   /* But control should never get here */
717    
718    case EL_ANY:    case EL_ANY:
719      case EL_ANYCRLF:
720    if (*(--p) == '\n' && p > startptr && p[-1] == '\r') p--;    if (*(--p) == '\n' && p > startptr && p[-1] == '\r') p--;
721    if (utf8) while ((*p & 0xc0) == 0x80) p--;    if (utf8) while ((*p & 0xc0) == 0x80) p--;
722    
# Line 671  switch(endlinetype) Line 745  switch(endlinetype)
745        }        }
746      else c = *((unsigned char *)pp);      else c = *((unsigned char *)pp);
747    
748      switch (c)      if (endlinetype == EL_ANYCRLF) switch (c)
749          {
750          case 0x0a:    /* LF */
751          case 0x0d:    /* CR */
752          return p;
753    
754          default:
755          break;
756          }
757    
758        else switch (c)
759        {        {
760        case 0x0a:    /* LF */        case 0x0a:    /* LF */
761        case 0x0b:    /* VT */        case 0x0b:    /* VT */
# Line 748  be in the middle third most of the time, Line 832  be in the middle third most of the time,
832  "before" context printing.  "before" context printing.
833    
834  Arguments:  Arguments:
835    in           the fopened FILE stream    handle       the fopened FILE stream for a normal file
836                   the gzFile pointer when reading is via libz
837                   the BZFILE pointer when reading is via libbz2
838      frtype       FR_PLAIN, FR_LIBZ, or FR_LIBBZ2
839    printname    the file name if it is to be printed for each match    printname    the file name if it is to be printed for each match
840                 or NULL if the file name is not to be printed                 or NULL if the file name is not to be printed
841                 it cannot be NULL if filenames[_nomatch]_only is set                 it cannot be NULL if filenames[_nomatch]_only is set
842    
843  Returns:       0 if there was at least one match  Returns:       0 if there was at least one match
844                 1 otherwise (no matches)                 1 otherwise (no matches)
845                   2 if there is a read error on a .bz2 file
846  */  */
847    
848  static int  static int
849  pcregrep(FILE *in, char *printname)  pcregrep(void *handle, int frtype, char *printname)
850  {  {
851  int rc = 1;  int rc = 1;
852  int linenumber = 1;  int linenumber = 1;
853  int lastmatchnumber = 0;  int lastmatchnumber = 0;
854  int count = 0;  int count = 0;
855    int filepos = 0;
856  int offsets[99];  int offsets[99];
857  char *lastmatchrestart = NULL;  char *lastmatchrestart = NULL;
858  char buffer[3*MBUFTHIRD];  char buffer[3*MBUFTHIRD];
# Line 771  char *ptr = buffer; Line 860  char *ptr = buffer;
860  char *endptr;  char *endptr;
861  size_t bufflength;  size_t bufflength;
862  BOOL endhyphenpending = FALSE;  BOOL endhyphenpending = FALSE;
863    FILE *in = NULL;                    /* Ensure initialized */
864    
865    #ifdef SUPPORT_LIBZ
866    gzFile ingz = NULL;
867    #endif
868    
869    #ifdef SUPPORT_LIBBZ2
870    BZFILE *inbz2 = NULL;
871    #endif
872    
873    
874    /* Do the first read into the start of the buffer and set up the pointer to end
875    of what we have. In the case of libz, a non-zipped .gz file will be read as a
876    plain file. However, if a .bz2 file isn't actually bzipped, the first read will
877    fail. */
878    
879    #ifdef SUPPORT_LIBZ
880    if (frtype == FR_LIBZ)
881      {
882      ingz = (gzFile)handle;
883      bufflength = gzread (ingz, buffer, 3*MBUFTHIRD);
884      }
885    else
886    #endif
887    
888  /* Do the first read into the start of the buffer and set up the pointer to  #ifdef SUPPORT_LIBBZ2
889  end of what we have. */  if (frtype == FR_LIBBZ2)
890      {
891      inbz2 = (BZFILE *)handle;
892      bufflength = BZ2_bzread(inbz2, buffer, 3*MBUFTHIRD);
893      if ((int)bufflength < 0) return 2;   /* Gotcha: bufflength is size_t; */
894      }                                    /* without the cast it is unsigned. */
895    else
896    #endif
897    
898      {
899      in = (FILE *)handle;
900      bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);
901      }
902    
 bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);  
903  endptr = buffer + bufflength;  endptr = buffer + bufflength;
904    
905  /* Loop while the current pointer is not at the end of the file. For large  /* Loop while the current pointer is not at the end of the file. For large
# Line 788  while (ptr < endptr) Line 912  while (ptr < endptr)
912    int i, endlinelength;    int i, endlinelength;
913    int mrc = 0;    int mrc = 0;
914    BOOL match = FALSE;    BOOL match = FALSE;
915      char *matchptr = ptr;
916    char *t = ptr;    char *t = ptr;
917    size_t length, linelength;    size_t length, linelength;
918    
# Line 800  while (ptr < endptr) Line 925  while (ptr < endptr)
925    
926    t = end_of_line(t, endptr, &endlinelength);    t = end_of_line(t, endptr, &endlinelength);
927    linelength = t - ptr - endlinelength;    linelength = t - ptr - endlinelength;
928    length = multiline? endptr - ptr : linelength;    length = multiline? (size_t)(endptr - ptr) : linelength;
929    
930    /* Extra processing for Jeffrey Friedl's debugging. */    /* Extra processing for Jeffrey Friedl's debugging. */
931    
# Line 850  while (ptr < endptr) Line 975  while (ptr < endptr)
975    }    }
976  #endif  #endif
977    
978      /* We come back here after a match when the -o option (only_matching) is set,
979      in order to find any further matches in the same line. */
980    
981      ONLY_MATCHING_RESTART:
982    
983    /* Run through all the patterns until one matches. Note that we don't include    /* Run through all the patterns until one matches. Note that we don't include
984    the final newline in the subject string. */    the final newline in the subject string. */
985    
986    for (i = 0; i < pattern_count; i++)    for (i = 0; i < pattern_count; i++)
987      {      {
988      mrc = pcre_exec(pattern_list[i], hints_list[i], ptr, length, 0, 0,      mrc = pcre_exec(pattern_list[i], hints_list[i], matchptr, length, 0, 0,
989        offsets, 99);        offsets, 99);
990      if (mrc >= 0) { match = TRUE; break; }      if (mrc >= 0) { match = TRUE; break; }
991      if (mrc != PCRE_ERROR_NOMATCH)      if (mrc != PCRE_ERROR_NOMATCH)
# Line 864  while (ptr < endptr) Line 993  while (ptr < endptr)
993        fprintf(stderr, "pcregrep: pcre_exec() error %d while matching ", mrc);        fprintf(stderr, "pcregrep: pcre_exec() error %d while matching ", mrc);
994        if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);        if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);
995        fprintf(stderr, "this line:\n");        fprintf(stderr, "this line:\n");
996        fwrite(ptr, 1, linelength, stderr);   /* In case binary zero included */        fwrite(matchptr, 1, linelength, stderr);  /* In case binary zero included */
997        fprintf(stderr, "\n");        fprintf(stderr, "\n");
998        if (error_count == 0 &&        if (error_count == 0 &&
999            (mrc == PCRE_ERROR_MATCHLIMIT || mrc == PCRE_ERROR_RECURSIONLIMIT))            (mrc == PCRE_ERROR_MATCHLIMIT || mrc == PCRE_ERROR_RECURSIONLIMIT))
# Line 911  while (ptr < endptr) Line 1040  while (ptr < endptr)
1040      else if (quiet) return 0;      else if (quiet) return 0;
1041    
1042      /* The --only-matching option prints just the substring that matched, and      /* The --only-matching option prints just the substring that matched, and
1043      does not pring any context. */      the --file-offsets and --line-offsets options output offsets for the
1044        matching substring (they both force --only-matching). None of these options
1045        prints any context. Afterwards, adjust the start and length, and then jump
1046        back to look for further matches in the same line. If we are in invert
1047        mode, however, nothing is printed - this could be still useful because the
1048        return code is set. */
1049    
1050      else if (only_matching)      else if (only_matching)
1051        {        {
1052        if (printname != NULL) fprintf(stdout, "%s:", printname);        if (!invert)
1053        if (number) fprintf(stdout, "%d:", linenumber);          {
1054        fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);          if (printname != NULL) fprintf(stdout, "%s:", printname);
1055        fprintf(stdout, "\n");          if (number) fprintf(stdout, "%d:", linenumber);
1056            if (line_offsets)
1057              fprintf(stdout, "%d,%d", (int)(matchptr + offsets[0] - ptr),
1058                offsets[1] - offsets[0]);
1059            else if (file_offsets)
1060              fprintf(stdout, "%d,%d", (int)(filepos + matchptr + offsets[0] - ptr),
1061                offsets[1] - offsets[0]);
1062            else
1063              {
1064              if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1065              fwrite(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1066              if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
1067              }
1068            fprintf(stdout, "\n");
1069            matchptr += offsets[1];
1070            length -= offsets[1];
1071            match = FALSE;
1072            goto ONLY_MATCHING_RESTART;
1073            }
1074        }        }
1075    
1076      /* This is the default case when none of the above options is set. We print      /* This is the default case when none of the above options is set. We print
# Line 1008  while (ptr < endptr) Line 1160  while (ptr < endptr)
1160    
1161        /* In multiline mode, we want to print to the end of the line in which        /* In multiline mode, we want to print to the end of the line in which
1162        the end of the matched string is found, so we adjust linelength and the        the end of the matched string is found, so we adjust linelength and the
1163        line number appropriately. Because the PCRE_FIRSTLINE option is set, the        line number appropriately, but only when there actually was a match
1164        start of the match will always be before the first newline sequence. */        (invert not set). Because the PCRE_FIRSTLINE option is set, the start of
1165          the match will always be before the first newline sequence. */
1166    
1167        if (multiline)        if (multiline)
1168          {          {
1169          int ellength;          int ellength;
1170          char *endmatch = ptr + offsets[1];          char *endmatch = ptr;
1171          t = ptr;          if (!invert)
         while (t < endmatch)  
1172            {            {
1173            t = end_of_line(t, endptr, &ellength);            endmatch += offsets[1];
1174            if (t <= endmatch) linenumber++; else break;            t = ptr;
1175              while (t < endmatch)
1176                {
1177                t = end_of_line(t, endptr, &ellength);
1178                if (t <= endmatch) linenumber++; else break;
1179                }
1180            }            }
1181          endmatch = end_of_line(endmatch, endptr, &ellength);          endmatch = end_of_line(endmatch, endptr, &ellength);
1182          linelength = endmatch - ptr - ellength;          linelength = endmatch - ptr - ellength;
# Line 1052  while (ptr < endptr) Line 1209  while (ptr < endptr)
1209          fprintf(stdout, "%c[%sm", 0x1b, colour_string);          fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1210          fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);          fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1211          fprintf(stdout, "%c[00m", 0x1b);          fprintf(stdout, "%c[00m", 0x1b);
1212          fwrite(ptr + offsets[1], 1, linelength - offsets[1], stdout);          fwrite(ptr + offsets[1], 1, (linelength + endlinelength) - offsets[1],
1213              stdout);
1214          }          }
1215        else fwrite(ptr, 1, linelength + endlinelength, stdout);        else fwrite(ptr, 1, linelength + endlinelength, stdout);
1216        }        }
# Line 1068  while (ptr < endptr) Line 1226  while (ptr < endptr)
1226      lastmatchnumber = linenumber + 1;      lastmatchnumber = linenumber + 1;
1227      }      }
1228    
1229    /* Advance to after the newline and increment the line number. */    /* For a match in multiline inverted mode (which of course did not cause
1230      anything to be printed), we have to move on to the end of the match before
1231      proceeding. */
1232    
1233      if (multiline && invert && match)
1234        {
1235        int ellength;
1236        char *endmatch = ptr + offsets[1];
1237        t = ptr;
1238        while (t < endmatch)
1239          {
1240          t = end_of_line(t, endptr, &ellength);
1241          if (t <= endmatch) linenumber++; else break;
1242          }
1243        endmatch = end_of_line(endmatch, endptr, &ellength);
1244        linelength = endmatch - ptr - ellength;
1245        }
1246    
1247      /* Advance to after the newline and increment the line number. The file
1248      offset to the current line is maintained in filepos. */
1249    
1250    ptr += linelength + endlinelength;    ptr += linelength + endlinelength;
1251      filepos += linelength + endlinelength;
1252    linenumber++;    linenumber++;
1253    
1254    /* If we haven't yet reached the end of the file (the buffer is full), and    /* If we haven't yet reached the end of the file (the buffer is full), and
# Line 1092  while (ptr < endptr) Line 1270  while (ptr < endptr)
1270    
1271      memmove(buffer, buffer + MBUFTHIRD, 2*MBUFTHIRD);      memmove(buffer, buffer + MBUFTHIRD, 2*MBUFTHIRD);
1272      ptr -= MBUFTHIRD;      ptr -= MBUFTHIRD;
1273    
1274    #ifdef SUPPORT_LIBZ
1275        if (frtype == FR_LIBZ)
1276          bufflength = 2*MBUFTHIRD +
1277            gzread (ingz, buffer + 2*MBUFTHIRD, MBUFTHIRD);
1278        else
1279    #endif
1280    
1281    #ifdef SUPPORT_LIBBZ2
1282        if (frtype == FR_LIBBZ2)
1283          bufflength = 2*MBUFTHIRD +
1284            BZ2_bzread(inbz2, buffer + 2*MBUFTHIRD, MBUFTHIRD);
1285        else
1286    #endif
1287    
1288      bufflength = 2*MBUFTHIRD + fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in);      bufflength = 2*MBUFTHIRD + fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in);
1289    
1290      endptr = buffer + bufflength;      endptr = buffer + bufflength;
1291    
1292      /* Adjust any last match point */      /* Adjust any last match point */
# Line 1156  grep_or_recurse(char *pathname, BOOL dir Line 1350  grep_or_recurse(char *pathname, BOOL dir
1350  {  {
1351  int rc = 1;  int rc = 1;
1352  int sep;  int sep;
1353  FILE *in;  int frtype;
1354    int pathlen;
1355    void *handle;
1356    FILE *in = NULL;           /* Ensure initialized */
1357    
1358    #ifdef SUPPORT_LIBZ
1359    gzFile ingz = NULL;
1360    #endif
1361    
1362    #ifdef SUPPORT_LIBBZ2
1363    BZFILE *inbz2 = NULL;
1364    #endif
1365    
1366  /* If the file name is "-" we scan stdin */  /* If the file name is "-" we scan stdin */
1367    
1368  if (strcmp(pathname, "-") == 0)  if (strcmp(pathname, "-") == 0)
1369    {    {
1370    return pcregrep(stdin,    return pcregrep(stdin, FR_PLAIN,
1371      (filenames > FN_DEFAULT || (filenames == FN_DEFAULT && !only_one_at_top))?      (filenames > FN_DEFAULT || (filenames == FN_DEFAULT && !only_one_at_top))?
1372        stdin_name : NULL);        stdin_name : NULL);
1373    }    }
1374    
   
1375  /* If the file is a directory, skip if skipping or if we are recursing, scan  /* If the file is a directory, skip if skipping or if we are recursing, scan
1376  each file within it, subject to any include or exclude patterns that were set.  each file and directory within it, subject to any include or exclude patterns
1377  The scanning code is localized so it can be made system-specific. */  that were set. The scanning code is localized so it can be made
1378    system-specific. */
1379    
1380  if ((sep = isdirectory(pathname)) != 0)  if ((sep = isdirectory(pathname)) != 0)
1381    {    {
# Line 1191  if ((sep = isdirectory(pathname)) != 0) Line 1396  if ((sep = isdirectory(pathname)) != 0)
1396    
1397      while ((nextfile = readdirectory(dir)) != NULL)      while ((nextfile = readdirectory(dir)) != NULL)
1398        {        {
1399        int frc, blen;        int frc, nflen;
1400        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);
1401        blen = strlen(buffer);        nflen = strlen(nextfile);
1402    
1403        if (exclude_compiled != NULL &&        if (isdirectory(buffer))
1404            pcre_exec(exclude_compiled, NULL, buffer, blen, 0, 0, NULL, 0) >= 0)          {
1405          continue;          if (exclude_dir_compiled != NULL &&
1406                pcre_exec(exclude_dir_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) >= 0)
1407        if (include_compiled != NULL &&            continue;
1408            pcre_exec(include_compiled, NULL, buffer, blen, 0, 0, NULL, 0) < 0)  
1409          continue;          if (include_dir_compiled != NULL &&
1410                pcre_exec(include_dir_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) < 0)
1411              continue;
1412            }
1413          else
1414            {
1415            if (exclude_compiled != NULL &&
1416                pcre_exec(exclude_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) >= 0)
1417              continue;
1418    
1419            if (include_compiled != NULL &&
1420                pcre_exec(include_compiled, NULL, nextfile, nflen, 0, 0, NULL, 0) < 0)
1421              continue;
1422            }
1423    
1424        frc = grep_or_recurse(buffer, dir_recurse, FALSE);        frc = grep_or_recurse(buffer, dir_recurse, FALSE);
1425        if (frc > 1) rc = frc;        if (frc > 1) rc = frc;
# Line 1224  skipping was not requested. The scan pro Line 1442  skipping was not requested. The scan pro
1442  argument at top level, we don't show the file name, unless we are only showing  argument at top level, we don't show the file name, unless we are only showing
1443  the file name, or the filename was forced (-H). */  the file name, or the filename was forced (-H). */
1444    
1445  in = fopen(pathname, "r");  pathlen = strlen(pathname);
1446  if (in == NULL)  
1447    /* Open using zlib if it is supported and the file name ends with .gz. */
1448    
1449    #ifdef SUPPORT_LIBZ
1450    if (pathlen > 3 && strcmp(pathname + pathlen - 3, ".gz") == 0)
1451      {
1452      ingz = gzopen(pathname, "rb");
1453      if (ingz == NULL)
1454        {
1455        if (!silent)
1456          fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pathname,
1457            strerror(errno));
1458        return 2;
1459        }
1460      handle = (void *)ingz;
1461      frtype = FR_LIBZ;
1462      }
1463    else
1464    #endif
1465    
1466    /* Otherwise open with bz2lib if it is supported and the name ends with .bz2. */
1467    
1468    #ifdef SUPPORT_LIBBZ2
1469    if (pathlen > 4 && strcmp(pathname + pathlen - 4, ".bz2") == 0)
1470      {
1471      inbz2 = BZ2_bzopen(pathname, "rb");
1472      handle = (void *)inbz2;
1473      frtype = FR_LIBBZ2;
1474      }
1475    else
1476    #endif
1477    
1478    /* Otherwise use plain fopen(). The label is so that we can come back here if
1479    an attempt to read a .bz2 file indicates that it really is a plain file. */
1480    
1481    #ifdef SUPPORT_LIBBZ2
1482    PLAIN_FILE:
1483    #endif
1484      {
1485      in = fopen(pathname, "r");
1486      handle = (void *)in;
1487      frtype = FR_PLAIN;
1488      }
1489    
1490    /* All the opening methods return errno when they fail. */
1491    
1492    if (handle == NULL)
1493    {    {
1494    if (!silent)    if (!silent)
1495      fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pathname,      fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pathname,
# Line 1233  if (in == NULL) Line 1497  if (in == NULL)
1497    return 2;    return 2;
1498    }    }
1499    
1500  rc = pcregrep(in, (filenames > FN_DEFAULT ||  /* Now grep the file */
1501    
1502    rc = pcregrep(handle, frtype, (filenames > FN_DEFAULT ||
1503    (filenames == FN_DEFAULT && !only_one_at_top))? pathname : NULL);    (filenames == FN_DEFAULT && !only_one_at_top))? pathname : NULL);
1504    
1505    /* Close in an appropriate manner. */
1506    
1507    #ifdef SUPPORT_LIBZ
1508    if (frtype == FR_LIBZ)
1509      gzclose(ingz);
1510    else
1511    #endif
1512    
1513    /* If it is a .bz2 file and the result is 2, it means that the first attempt to
1514    read failed. If the error indicates that the file isn't in fact bzipped, try
1515    again as a normal file. */
1516    
1517    #ifdef SUPPORT_LIBBZ2
1518    if (frtype == FR_LIBBZ2)
1519      {
1520      if (rc == 2)
1521        {
1522        int errnum;
1523        const char *err = BZ2_bzerror(inbz2, &errnum);
1524        if (errnum == BZ_DATA_ERROR_MAGIC)
1525          {
1526          BZ2_bzclose(inbz2);
1527          goto PLAIN_FILE;
1528          }
1529        else if (!silent)
1530          fprintf(stderr, "pcregrep: Failed to read %s using bzlib: %s\n",
1531            pathname, err);
1532        }
1533      BZ2_bzclose(inbz2);
1534      }
1535    else
1536    #endif
1537    
1538    /* Normal file close */
1539    
1540  fclose(in);  fclose(in);
1541    
1542    /* Pass back the yield from pcregrep(). */
1543    
1544  return rc;  return rc;
1545  }  }
1546    
# Line 1257  for (op = optionlist; op->one_char != 0; Line 1561  for (op = optionlist; op->one_char != 0;
1561    if (op->one_char > 0) fprintf(stderr, "%c", op->one_char);    if (op->one_char > 0) fprintf(stderr, "%c", op->one_char);
1562    }    }
1563  fprintf(stderr, "] [long options] [pattern] [files]\n");  fprintf(stderr, "] [long options] [pattern] [files]\n");
1564  fprintf(stderr, "Type `pcregrep --help' for more information.\n");  fprintf(stderr, "Type `pcregrep --help' for more information and the long "
1565      "options.\n");
1566  return rc;  return rc;
1567  }  }
1568    
# Line 1276  option_item *op; Line 1581  option_item *op;
1581  printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n");  printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n");
1582  printf("Search for PATTERN in each FILE or standard input.\n");  printf("Search for PATTERN in each FILE or standard input.\n");
1583  printf("PATTERN must be present if neither -e nor -f is used.\n");  printf("PATTERN must be present if neither -e nor -f is used.\n");
1584  printf("\"-\" can be used as a file name to mean STDIN.\n\n");  printf("\"-\" can be used as a file name to mean STDIN.\n");
1585  printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n");  
1586    #ifdef SUPPORT_LIBZ
1587    printf("Files whose names end in .gz are read using zlib.\n");
1588    #endif
1589    
1590    #ifdef SUPPORT_LIBBZ2
1591    printf("Files whose names end in .bz2 are read using bzlib2.\n");
1592    #endif
1593    
1594    #if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2
1595    printf("Other files and the standard input are read as plain files.\n\n");
1596    #else
1597    printf("All files are read as plain files, without any interpretation.\n\n");
1598    #endif
1599    
1600    printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n");
1601  printf("Options:\n");  printf("Options:\n");
1602    
1603  for (op = optionlist; op->one_char != 0; op++)  for (op = optionlist; op->one_char != 0; op++)
# Line 1286  for (op = optionlist; op->one_char != 0; Line 1605  for (op = optionlist; op->one_char != 0;
1605    int n;    int n;
1606    char s[4];    char s[4];
1607    if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, "   ");    if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, "   ");
1608    printf("  %s --%s%n", s, op->long_name, &n);    n = 30 - printf("  %s --%s", s, op->long_name);
   n = 30 - n;  
1609    if (n < 1) n = 1;    if (n < 1) n = 1;
1610    printf("%.*s%s\n", n, "                    ", op->help_text);    printf("%.*s%s\n", n, "                    ", op->help_text);
1611    }    }
# Line 1312  handle_option(int letter, int options) Line 1630  handle_option(int letter, int options)
1630  {  {
1631  switch(letter)  switch(letter)
1632    {    {
1633      case N_FOFFSETS: file_offsets = TRUE; break;
1634    case N_HELP: help(); exit(0);    case N_HELP: help(); exit(0);
1635      case N_LOFFSETS: line_offsets = number = TRUE; break;
1636    case 'c': count_only = TRUE; break;    case 'c': count_only = TRUE; break;
1637    case 'F': process_options |= PO_FIXED_STRINGS; break;    case 'F': process_options |= PO_FIXED_STRINGS; break;
1638    case 'H': filenames = FN_FORCE; break;    case 'H': filenames = FN_FORCE; break;
# Line 1408  sprintf(buffer, "%s%.*s%s", prefix[proce Line 1728  sprintf(buffer, "%s%.*s%s", prefix[proce
1728    suffix[process_options]);    suffix[process_options]);
1729  pattern_list[pattern_count] =  pattern_list[pattern_count] =
1730    pcre_compile(buffer, options, &error, &errptr, pcretables);    pcre_compile(buffer, options, &error, &errptr, pcretables);
1731  if (pattern_list[pattern_count++] != NULL) return TRUE;  if (pattern_list[pattern_count] != NULL)
1732      {
1733      pattern_count++;
1734      return TRUE;
1735      }
1736    
1737  /* Handle compile errors */  /* Handle compile errors */
1738    
# Line 1466  if ((process_options & PO_FIXED_STRINGS) Line 1790  if ((process_options & PO_FIXED_STRINGS)
1790      char *p = end_of_line(pattern, eop, &ellength);      char *p = end_of_line(pattern, eop, &ellength);
1791      if (ellength == 0)      if (ellength == 0)
1792        return compile_single_pattern(pattern, options, filename, count);        return compile_single_pattern(pattern, options, filename, count);
1793      sprintf(buffer, "%.*s", p - pattern - ellength, pattern);      sprintf(buffer, "%.*s", (int)(p - pattern - ellength), pattern);
1794      pattern = p;      pattern = p;
1795      if (!compile_single_pattern(buffer, options, filename, count))      if (!compile_single_pattern(buffer, options, filename, count))
1796        return FALSE;        return FALSE;
# Line 1490  int i, j; Line 1814  int i, j;
1814  int rc = 1;  int rc = 1;
1815  int pcre_options = 0;  int pcre_options = 0;
1816  int cmd_pattern_count = 0;  int cmd_pattern_count = 0;
1817    int hint_count = 0;
1818  int errptr;  int errptr;
1819  BOOL only_one_at_top;  BOOL only_one_at_top;
1820  char *patterns[MAX_PATTERN_COUNT];  char *patterns[MAX_PATTERN_COUNT];
# Line 1507  switch(i) Line 1832  switch(i)
1832    case '\r':               newline = (char *)"cr"; break;    case '\r':               newline = (char *)"cr"; break;
1833    case ('\r' << 8) | '\n': newline = (char *)"crlf"; break;    case ('\r' << 8) | '\n': newline = (char *)"crlf"; break;
1834    case -1:                 newline = (char *)"any"; break;    case -1:                 newline = (char *)"any"; break;
1835      case -2:                 newline = (char *)"anycrlf"; break;
1836    }    }
1837    
1838  /* Process the options */  /* Process the options */
# Line 1564  for (i = 1; i < argc; i++) Line 1890  for (i = 1; i < argc; i++)
1890          else                 /* Special case xxx=data */          else                 /* Special case xxx=data */
1891            {            {
1892            int oplen = equals - op->long_name;            int oplen = equals - op->long_name;
1893            int arglen = (argequals == NULL)? strlen(arg) : argequals - arg;            int arglen = (argequals == NULL)? (int)strlen(arg) : argequals - arg;
1894            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)
1895              {              {
1896              option_data = arg + arglen;              option_data = arg + arglen;
# Line 1583  for (i = 1; i < argc; i++) Line 1909  for (i = 1; i < argc; i++)
1909          char buff2[24];          char buff2[24];
1910          int baselen = opbra - op->long_name;          int baselen = opbra - op->long_name;
1911          sprintf(buff1, "%.*s", baselen, op->long_name);          sprintf(buff1, "%.*s", baselen, op->long_name);
1912          sprintf(buff2, "%s%.*s", buff1, strlen(op->long_name) - baselen - 2,          sprintf(buff2, "%s%.*s", buff1,
1913            opbra + 1);            (int)strlen(op->long_name) - baselen - 2, opbra + 1);
1914          if (strcmp(arg, buff1) == 0 || strcmp(arg, buff2) == 0)          if (strcmp(arg, buff1) == 0 || strcmp(arg, buff2) == 0)
1915            break;            break;
1916          }          }
# Line 1743  if (both_context > 0) Line 2069  if (both_context > 0)
2069    if (before_context == 0) before_context = both_context;    if (before_context == 0) before_context = both_context;
2070    }    }
2071    
2072    /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.
2073    However, the latter two set the only_matching flag. */
2074    
2075    if ((only_matching && (file_offsets || line_offsets)) ||
2076        (file_offsets && line_offsets))
2077      {
2078      fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "
2079        "and/or --line-offsets\n");
2080      exit(usage(2));
2081      }
2082    
2083    if (file_offsets || line_offsets) only_matching = TRUE;
2084    
2085  /* If a locale has not been provided as an option, see if the LC_CTYPE or  /* If a locale has not been provided as an option, see if the LC_CTYPE or
2086  LC_ALL environment variable is set, and if so, use it. */  LC_ALL environment variable is set, and if so, use it. */
2087    
# Line 1814  else if (strcmp(newline, "any") == 0 || Line 2153  else if (strcmp(newline, "any") == 0 ||
2153    pcre_options |= PCRE_NEWLINE_ANY;    pcre_options |= PCRE_NEWLINE_ANY;
2154    endlinetype = EL_ANY;    endlinetype = EL_ANY;
2155    }    }
2156    else if (strcmp(newline, "anycrlf") == 0 || strcmp(newline, "ANYCRLF") == 0)
2157      {
2158      pcre_options |= PCRE_NEWLINE_ANYCRLF;
2159      endlinetype = EL_ANYCRLF;
2160      }
2161  else  else
2162    {    {
2163    fprintf(stderr, "pcregrep: Invalid newline specifier \"%s\"\n", newline);    fprintf(stderr, "pcregrep: Invalid newline specifier \"%s\"\n", newline);
# Line 1942  for (j = 0; j < pattern_count; j++) Line 2286  for (j = 0; j < pattern_count; j++)
2286      fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error);      fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error);
2287      goto EXIT2;      goto EXIT2;
2288      }      }
2289      hint_count++;
2290    }    }
2291    
2292  /* If there are include or exclude patterns, compile them. */  /* If there are include or exclude patterns, compile them. */
# Line 1970  if (include_pattern != NULL) Line 2315  if (include_pattern != NULL)
2315      }      }
2316    }    }
2317    
2318    if (exclude_dir_pattern != NULL)
2319      {
2320      exclude_dir_compiled = pcre_compile(exclude_dir_pattern, 0, &error, &errptr,
2321        pcretables);
2322      if (exclude_dir_compiled == NULL)
2323        {
2324        fprintf(stderr, "pcregrep: Error in 'exclude_dir' regex at offset %d: %s\n",
2325          errptr, error);
2326        goto EXIT2;
2327        }
2328      }
2329    
2330    if (include_dir_pattern != NULL)
2331      {
2332      include_dir_compiled = pcre_compile(include_dir_pattern, 0, &error, &errptr,
2333        pcretables);
2334      if (include_dir_compiled == NULL)
2335        {
2336        fprintf(stderr, "pcregrep: Error in 'include_dir' regex at offset %d: %s\n",
2337          errptr, error);
2338        goto EXIT2;
2339        }
2340      }
2341    
2342  /* If there are no further arguments, do the business on stdin and exit. */  /* If there are no further arguments, do the business on stdin and exit. */
2343    
2344  if (i >= argc)  if (i >= argc)
2345    {    {
2346    rc = pcregrep(stdin, (filenames > FN_DEFAULT)? stdin_name : NULL);    rc = pcregrep(stdin, FR_PLAIN, (filenames > FN_DEFAULT)? stdin_name : NULL);
2347    goto EXIT;    goto EXIT;
2348    }    }
2349    
# Line 2001  if (pattern_list != NULL) Line 2370  if (pattern_list != NULL)
2370    }    }
2371  if (hints_list != NULL)  if (hints_list != NULL)
2372    {    {
2373    for (i = 0; i < pattern_count; i++) free(hints_list[i]);    for (i = 0; i < hint_count; i++) free(hints_list[i]);
2374    free(hints_list);    free(hints_list);
2375    }    }
2376  return rc;  return rc;

Legend:
Removed from v.137  
changed lines
  Added in v.377

  ViewVC Help
Powered by ViewVC 1.1.5