/[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 345 by ph10, Mon Apr 28 15:10:02 2008 UTC revision 589 by ph10, Sat Jan 15 11:31:39 2011 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-2008 University of Cambridge             Copyright (c) 1997-2011 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 71  POSSIBILITY OF SUCH DAMAGE. Line 71  POSSIBILITY OF SUCH DAMAGE.
71  typedef int BOOL;  typedef int BOOL;
72    
73  #define MAX_PATTERN_COUNT 100  #define MAX_PATTERN_COUNT 100
74    #define OFFSET_SIZE 99
75    
76  #if BUFSIZ > 8192  #if BUFSIZ > 8192
77  #define MBUFTHIRD BUFSIZ  #define MBUFTHIRD BUFSIZ
# Line 82  typedef int BOOL; Line 83  typedef int BOOL;
83  output. The order is important; it is assumed that a file name is wanted for  output. The order is important; it is assumed that a file name is wanted for
84  all values greater than FN_DEFAULT. */  all values greater than FN_DEFAULT. */
85    
86  enum { FN_NONE, FN_DEFAULT, FN_ONLY, FN_NOMATCH_ONLY, FN_FORCE };  enum { FN_NONE, FN_DEFAULT, FN_MATCH_ONLY, FN_NOMATCH_ONLY, FN_FORCE };
87    
88  /* File reading styles */  /* File reading styles */
89    
# Line 103  enum { DEE_READ, DEE_SKIP }; Line 104  enum { DEE_READ, DEE_SKIP };
104    
105  enum { EL_LF, EL_CR, EL_CRLF, EL_ANY, EL_ANYCRLF };  enum { EL_LF, EL_CR, EL_CRLF, EL_ANY, EL_ANYCRLF };
106    
107    /* In newer versions of gcc, with FORTIFY_SOURCE set (the default in some
108    environments), a warning is issued if the value of fwrite() is ignored.
109    Unfortunately, casting to (void) does not suppress the warning. To get round
110    this, we use a macro that compiles a fudge. Oddly, this does not also seem to
111    apply to fprintf(). */
112    
113    #define FWRITE(a,b,c,d) if (fwrite(a,b,c,d)) {}
114    
115    
116    
117  /*************************************************  /*************************************************
# Line 154  static int dee_action = dee_READ; Line 163  static int dee_action = dee_READ;
163  static int DEE_action = DEE_READ;  static int DEE_action = DEE_READ;
164  static int error_count = 0;  static int error_count = 0;
165  static int filenames = FN_DEFAULT;  static int filenames = FN_DEFAULT;
166    static int only_matching = -1;
167  static int process_options = 0;  static int process_options = 0;
168    
169    static unsigned long int match_limit = 0;
170    static unsigned long int match_limit_recursion = 0;
171    
172  static BOOL count_only = FALSE;  static BOOL count_only = FALSE;
173  static BOOL do_colour = FALSE;  static BOOL do_colour = FALSE;
174  static BOOL file_offsets = FALSE;  static BOOL file_offsets = FALSE;
175  static BOOL hyphenpending = FALSE;  static BOOL hyphenpending = FALSE;
176  static BOOL invert = FALSE;  static BOOL invert = FALSE;
177    static BOOL line_buffered = FALSE;
178  static BOOL line_offsets = FALSE;  static BOOL line_offsets = FALSE;
179  static BOOL multiline = FALSE;  static BOOL multiline = FALSE;
180  static BOOL number = FALSE;  static BOOL number = FALSE;
181  static BOOL only_matching = FALSE;  static BOOL omit_zero_count = FALSE;
182    static BOOL resource_error = FALSE;
183  static BOOL quiet = FALSE;  static BOOL quiet = FALSE;
184  static BOOL silent = FALSE;  static BOOL silent = FALSE;
185  static BOOL utf8 = FALSE;  static BOOL utf8 = FALSE;
186    
187  /* Structure for options and list of them */  /* Structure for options and list of them */
188    
189  enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_OP_NUMBER,  enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_LONGNUMBER,
190         OP_PATLIST };         OP_OP_NUMBER, OP_PATLIST };
191    
192  typedef struct option_item {  typedef struct option_item {
193    int type;    int type;
# Line 196  used to identify them. */ Line 211  used to identify them. */
211  #define N_NULL         (-9)  #define N_NULL         (-9)
212  #define N_LOFFSETS     (-10)  #define N_LOFFSETS     (-10)
213  #define N_FOFFSETS     (-11)  #define N_FOFFSETS     (-11)
214    #define N_LBUFFER      (-12)
215    #define N_M_LIMIT      (-13)
216    #define N_M_LIMIT_REC  (-14)
217    
218  static option_item optionlist[] = {  static option_item optionlist[] = {
219    { OP_NODATA,    N_NULL,   NULL,              "",              "  terminate options" },    { OP_NODATA,     N_NULL,   NULL,              "",              "  terminate options" },
220    { OP_NODATA,    N_HELP,   NULL,              "help",          "display this help and exit" },    { OP_NODATA,     N_HELP,   NULL,              "help",          "display this help and exit" },
221    { OP_NUMBER,    'A',      &after_context,    "after-context=number", "set number of following context lines" },    { OP_NUMBER,     'A',      &after_context,    "after-context=number", "set number of following context lines" },
222    { OP_NUMBER,    'B',      &before_context,   "before-context=number", "set number of prior context lines" },    { OP_NUMBER,     'B',      &before_context,   "before-context=number", "set number of prior context lines" },
223    { OP_OP_STRING, N_COLOUR, &colour_option,    "color=option",  "matched text color option" },    { OP_OP_STRING,  N_COLOUR, &colour_option,    "color=option",  "matched text color option" },
224    { OP_NUMBER,    'C',      &both_context,     "context=number", "set number of context lines, before & after" },    { OP_OP_STRING,  N_COLOUR, &colour_option,    "colour=option", "matched text colour option" },
225    { OP_NODATA,    'c',      NULL,              "count",         "print only a count of matching lines per FILE" },    { OP_NUMBER,     'C',      &both_context,     "context=number", "set number of context lines, before & after" },
226    { OP_OP_STRING, N_COLOUR, &colour_option,    "colour=option", "matched text colour option" },    { OP_NODATA,     'c',      NULL,              "count",         "print only a count of matching lines per FILE" },
227    { OP_STRING,    'D',      &DEE_option,       "devices=action","how to handle devices, FIFOs, and sockets" },    { OP_STRING,     'D',      &DEE_option,       "devices=action","how to handle devices, FIFOs, and sockets" },
228    { OP_STRING,    'd',      &dee_option,       "directories=action", "how to handle directories" },    { OP_STRING,     'd',      &dee_option,       "directories=action", "how to handle directories" },
229    { OP_PATLIST,   'e',      NULL,              "regex(p)",      "specify pattern (may be used more than once)" },    { OP_PATLIST,    'e',      NULL,              "regex(p)=pattern", "specify pattern (may be used more than once)" },
230    { 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" },
231    { OP_STRING,    'f',      &pattern_filename, "file=path",     "read patterns from file" },    { OP_STRING,     'f',      &pattern_filename, "file=path",     "read patterns from file" },
232    { OP_NODATA,    N_FOFFSETS, NULL,            "file-offsets",  "output file offsets, not text" },    { OP_NODATA,     N_FOFFSETS, NULL,            "file-offsets",  "output file offsets, not text" },
233    { OP_NODATA,    'H',      NULL,              "with-filename", "force the prefixing filename on output" },    { OP_NODATA,     'H',      NULL,              "with-filename", "force the prefixing filename on output" },
234    { OP_NODATA,    'h',      NULL,              "no-filename",   "suppress the prefixing filename on output" },    { OP_NODATA,     'h',      NULL,              "no-filename",   "suppress the prefixing filename on output" },
235    { OP_NODATA,    'i',      NULL,              "ignore-case",   "ignore case distinctions" },    { OP_NODATA,     'i',      NULL,              "ignore-case",   "ignore case distinctions" },
236    { 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" },
237    { 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" },
238    { 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" },
239    { OP_NODATA,    N_LOFFSETS, NULL,            "line-offsets",  "output line numbers and offsets, not text" },    { OP_NODATA,     N_LBUFFER, NULL,             "line-buffered", "use line buffering" },
240    { OP_STRING,    N_LOCALE, &locale,           "locale=locale", "use the named locale" },    { OP_NODATA,     N_LOFFSETS, NULL,            "line-offsets",  "output line numbers and offsets, not text" },
241    { OP_NODATA,    'M',      NULL,              "multiline",     "run in multiline mode" },    { OP_STRING,     N_LOCALE, &locale,           "locale=locale", "use the named locale" },
242    { OP_STRING,    'N',      &newline,          "newline=type",  "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" },    { OP_LONGNUMBER, N_M_LIMIT, &match_limit,     "match-limit=number", "set PCRE match limit option" },
243    { OP_NODATA,    'n',      NULL,              "line-number",   "print line number with output lines" },    { OP_LONGNUMBER, N_M_LIMIT_REC, &match_limit_recursion, "recursion-limit=number", "set PCRE match recursion limit option" },
244    { OP_NODATA,    'o',      NULL,              "only-matching", "show only the part of the line that matched" },    { OP_NODATA,     'M',      NULL,              "multiline",     "run in multiline mode" },
245    { OP_NODATA,    'q',      NULL,              "quiet",         "suppress output, just set return code" },    { OP_STRING,     'N',      &newline,          "newline=type",  "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" },
246    { OP_NODATA,    'r',      NULL,              "recursive",     "recursively scan sub-directories" },    { OP_NODATA,     'n',      NULL,              "line-number",   "print line number with output lines" },
247    { OP_STRING,    N_EXCLUDE,&exclude_pattern,  "exclude=pattern","exclude matching files when recursing" },    { OP_OP_NUMBER,  'o',      &only_matching,    "only-matching=n", "show only the part of the line that matched" },
248    { OP_STRING,    N_INCLUDE,&include_pattern,  "include=pattern","include matching files when recursing" },    { OP_NODATA,     'q',      NULL,              "quiet",         "suppress output, just set return code" },
249      { OP_NODATA,     'r',      NULL,              "recursive",     "recursively scan sub-directories" },
250      { OP_STRING,     N_EXCLUDE,&exclude_pattern,  "exclude=pattern","exclude matching files when recursing" },
251      { OP_STRING,     N_INCLUDE,&include_pattern,  "include=pattern","include matching files when recursing" },
252      { OP_STRING,     N_EXCLUDE_DIR,&exclude_dir_pattern, "exclude-dir=pattern","exclude matching directories when recursing" },
253      { OP_STRING,     N_INCLUDE_DIR,&include_dir_pattern, "include-dir=pattern","include matching directories when recursing" },
254    
255      /* These two were accidentally implemented with underscores instead of
256      hyphens in the option names. As this was not discovered for several releases,
257      the incorrect versions are left in the table for compatibility. However, the
258      --help function misses out any option that has an underscore in its name. */
259    
260    { OP_STRING,    N_EXCLUDE_DIR,&exclude_dir_pattern, "exclude_dir=pattern","exclude matching directories when recursing" },    { OP_STRING,    N_EXCLUDE_DIR,&exclude_dir_pattern, "exclude_dir=pattern","exclude matching directories when recursing" },
261    { OP_STRING,    N_INCLUDE_DIR,&include_dir_pattern, "include_dir=pattern","include matching directories when recursing" },    { OP_STRING,    N_INCLUDE_DIR,&include_dir_pattern, "include_dir=pattern","include matching directories when recursing" },
262    
263  #ifdef JFRIEDL_DEBUG  #ifdef JFRIEDL_DEBUG
264    { 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" },
265  #endif  #endif
# Line 266  const char utf8_table4[] = { Line 296  const char utf8_table4[] = {
296    
297    
298  /*************************************************  /*************************************************
299    *         Exit from the program                  *
300    *************************************************/
301    
302    /* If there has been a resource error, give a suitable message.
303    
304    Argument:  the return code
305    Returns:   does not return
306    */
307    
308    static void
309    pcregrep_exit(int rc)
310    {
311    if (resource_error)
312      {
313      fprintf(stderr, "pcregrep: Error %d or %d means that a resource limit "
314        "was exceeded.\n", PCRE_ERROR_MATCHLIMIT, PCRE_ERROR_RECURSIONLIMIT);
315      fprintf(stderr, "pcregrep: Check your regex for nested unlimited loops.\n");
316      }
317    
318    exit(rc);
319    }
320    
321    
322    /*************************************************
323  *            OS-specific functions               *  *            OS-specific functions               *
324  *************************************************/  *************************************************/
325    
# Line 329  return (statbuf.st_mode & S_IFMT) == S_I Line 383  return (statbuf.st_mode & S_IFMT) == S_I
383  }  }
384    
385    
386  /************* Test stdout for being a terminal in Unix **********/  /************* Test for a terminal in Unix **********/
387    
388  static BOOL  static BOOL
389  is_stdout_tty(void)  is_stdout_tty(void)
# Line 337  is_stdout_tty(void) Line 391  is_stdout_tty(void)
391  return isatty(fileno(stdout));  return isatty(fileno(stdout));
392  }  }
393    
394    static BOOL
395    is_file_tty(FILE *f)
396    {
397    return isatty(fileno(f));
398    }
399    
400    
401  /************* Directory scanning in Win32 ***********/  /************* Directory scanning in Win32 ***********/
402    
# Line 344  return isatty(fileno(stdout)); Line 404  return isatty(fileno(stdout));
404  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES
405  when it did not exist. David Byron added a patch that moved the #include of  when it did not exist. David Byron added a patch that moved the #include of
406  <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.  <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.
407  */  The double test below stops gcc 4.4.4 grumbling that HAVE_WINDOWS_H is
408    undefined when it is indeed undefined. */
409    
410  #elif HAVE_WINDOWS_H  #elif defined HAVE_WINDOWS_H && HAVE_WINDOWS_H
411    
412  #ifndef STRICT  #ifndef STRICT
413  # define STRICT  # define STRICT
# Line 390  dir = (directory_type *) malloc(sizeof(* Line 451  dir = (directory_type *) malloc(sizeof(*
451  if ((pattern == NULL) || (dir == NULL))  if ((pattern == NULL) || (dir == NULL))
452    {    {
453    fprintf(stderr, "pcregrep: malloc failed\n");    fprintf(stderr, "pcregrep: malloc failed\n");
454    exit(2);    pcregrep_exit(2);
455    }    }
456  memcpy(pattern, filename, len);  memcpy(pattern, filename, len);
457  memcpy(&(pattern[len]), "\\*", 3);  memcpy(&(pattern[len]), "\\*", 3);
# Line 449  return !isdirectory(filename); Line 510  return !isdirectory(filename);
510  }  }
511    
512    
513  /************* Test stdout for being a terminal in Win32 **********/  /************* Test for a terminal in Win32 **********/
514    
515  /* I don't know how to do this; assume never */  /* I don't know how to do this; assume never */
516    
# Line 459  is_stdout_tty(void) Line 520  is_stdout_tty(void)
520  return FALSE;  return FALSE;
521  }  }
522    
523    static BOOL
524    is_file_tty(FILE *f)
525    {
526    return FALSE;
527    }
528    
529    
530  /************* Directory scanning when we can't do it ***********/  /************* Directory scanning when we can't do it ***********/
531    
# Line 481  void closedirectory(directory_type *dir) Line 548  void closedirectory(directory_type *dir)
548  int isregfile(char *filename) { return 1; }  int isregfile(char *filename) { return 1; }
549    
550    
551  /************* Test stdout for being a terminal when we can't do it **********/  /************* Test for a terminal when we can't do it **********/
552    
553  static BOOL  static BOOL
554  is_stdout_tty(void)  is_stdout_tty(void)
# Line 489  is_stdout_tty(void) Line 556  is_stdout_tty(void)
556  return FALSE;  return FALSE;
557  }  }
558    
559    static BOOL
560    is_file_tty(FILE *f)
561    {
562    return FALSE;
563    }
564    
565  #endif  #endif
566    
# Line 517  return sys_errlist[n]; Line 589  return sys_errlist[n];
589    
590    
591  /*************************************************  /*************************************************
592    *            Read one line of input              *
593    *************************************************/
594    
595    /* Normally, input is read using fread() into a large buffer, so many lines may
596    be read at once. However, doing this for tty input means that no output appears
597    until a lot of input has been typed. Instead, tty input is handled line by
598    line. We cannot use fgets() for this, because it does not stop at a binary
599    zero, and therefore there is no way of telling how many characters it has read,
600    because there may be binary zeros embedded in the data.
601    
602    Arguments:
603      buffer     the buffer to read into
604      length     the maximum number of characters to read
605      f          the file
606    
607    Returns:     the number of characters read, zero at end of file
608    */
609    
610    static int
611    read_one_line(char *buffer, int length, FILE *f)
612    {
613    int c;
614    int yield = 0;
615    while ((c = fgetc(f)) != EOF)
616      {
617      buffer[yield++] = c;
618      if (c == '\n' || yield >= length) break;
619      }
620    return yield;
621    }
622    
623    
624    
625    /*************************************************
626  *             Find end of line                   *  *             Find end of line                   *
627  *************************************************/  *************************************************/
628    
# Line 528  Arguments: Line 634  Arguments:
634    endptr    end of available data    endptr    end of available data
635    lenptr    where to put the length of the eol sequence    lenptr    where to put the length of the eol sequence
636    
637  Returns:    pointer to the last byte of the line  Returns:    pointer to the last byte of the line, including the newline byte(s)
638  */  */
639    
640  static char *  static char *
# Line 811  if (after_context > 0 && lastmatchnumber Line 917  if (after_context > 0 && lastmatchnumber
917      if (printname != NULL) fprintf(stdout, "%s-", printname);      if (printname != NULL) fprintf(stdout, "%s-", printname);
918      if (number) fprintf(stdout, "%d-", lastmatchnumber++);      if (number) fprintf(stdout, "%d-", lastmatchnumber++);
919      pp = end_of_line(pp, endptr, &ellength);      pp = end_of_line(pp, endptr, &ellength);
920      fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout);      FWRITE(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
921      lastmatchrestart = pp;      lastmatchrestart = pp;
922      }      }
923    hyphenpending = TRUE;    hyphenpending = TRUE;
# Line 821  if (after_context > 0 && lastmatchnumber Line 927  if (after_context > 0 && lastmatchnumber
927    
928    
929  /*************************************************  /*************************************************
930    *   Apply patterns to subject till one matches   *
931    *************************************************/
932    
933    /* This function is called to run through all patterns, looking for a match. It
934    is used multiple times for the same subject when colouring is enabled, in order
935    to find all possible matches.
936    
937    Arguments:
938      matchptr    the start of the subject
939      length      the length of the subject to match
940      offsets     the offets vector to fill in
941      mrc         address of where to put the result of pcre_exec()
942    
943    Returns:      TRUE if there was a match
944                  FALSE if there was no match
945                  invert if there was a non-fatal error
946    */
947    
948    static BOOL
949    match_patterns(char *matchptr, size_t length, int *offsets, int *mrc)
950    {
951    int i;
952    size_t slen = length;
953    const char *msg = "this text:\n\n";
954    if (slen > 200)
955      {
956      slen = 200;
957      msg = "text that starts:\n\n";
958      }
959    for (i = 0; i < pattern_count; i++)
960      {
961      *mrc = pcre_exec(pattern_list[i], hints_list[i], matchptr, (int)length, 0,
962        PCRE_NOTEMPTY, offsets, OFFSET_SIZE);
963      if (*mrc >= 0) return TRUE;
964      if (*mrc == PCRE_ERROR_NOMATCH) continue;
965      fprintf(stderr, "pcregrep: pcre_exec() gave error %d while matching ", *mrc);
966      if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);
967      fprintf(stderr, "%s", msg);
968      FWRITE(matchptr, 1, slen, stderr);   /* In case binary zero included */
969      fprintf(stderr, "\n\n");
970      if (*mrc == PCRE_ERROR_MATCHLIMIT || *mrc == PCRE_ERROR_RECURSIONLIMIT)
971        resource_error = TRUE;
972      if (error_count++ > 20)
973        {
974        fprintf(stderr, "pcregrep: Too many errors - abandoned.\n");
975        pcregrep_exit(2);
976        }
977      return invert;    /* No more matching; don't show the line again */
978      }
979    
980    return FALSE;  /* No match, no errors */
981    }
982    
983    
984    
985    /*************************************************
986  *            Grep an individual file             *  *            Grep an individual file             *
987  *************************************************/  *************************************************/
988    
# Line 853  int linenumber = 1; Line 1015  int linenumber = 1;
1015  int lastmatchnumber = 0;  int lastmatchnumber = 0;
1016  int count = 0;  int count = 0;
1017  int filepos = 0;  int filepos = 0;
1018  int offsets[99];  int offsets[OFFSET_SIZE];
1019  char *lastmatchrestart = NULL;  char *lastmatchrestart = NULL;
1020  char buffer[3*MBUFTHIRD];  char buffer[3*MBUFTHIRD];
1021  char *ptr = buffer;  char *ptr = buffer;
1022  char *endptr;  char *endptr;
1023  size_t bufflength;  size_t bufflength;
1024  BOOL endhyphenpending = FALSE;  BOOL endhyphenpending = FALSE;
1025    BOOL input_line_buffered = line_buffered;
1026  FILE *in = NULL;                    /* Ensure initialized */  FILE *in = NULL;                    /* Ensure initialized */
1027    
1028  #ifdef SUPPORT_LIBZ  #ifdef SUPPORT_LIBZ
# Line 897  else Line 1060  else
1060    
1061    {    {
1062    in = (FILE *)handle;    in = (FILE *)handle;
1063    bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);    if (is_file_tty(in)) input_line_buffered = TRUE;
1064      bufflength = input_line_buffered?
1065        read_one_line(buffer, 3*MBUFTHIRD, in) :
1066        fread(buffer, 1, 3*MBUFTHIRD, in);
1067    }    }
1068    
1069  endptr = buffer + bufflength;  endptr = buffer + bufflength;
# Line 909  way, the buffer is shifted left and re-f Line 1075  way, the buffer is shifted left and re-f
1075    
1076  while (ptr < endptr)  while (ptr < endptr)
1077    {    {
1078    int i, endlinelength;    int endlinelength;
1079    int mrc = 0;    int mrc = 0;
1080    BOOL match = FALSE;    BOOL match;
1081    char *matchptr = ptr;    char *matchptr = ptr;
1082    char *t = ptr;    char *t = ptr;
1083    size_t length, linelength;    size_t length, linelength;
# Line 919  while (ptr < endptr) Line 1085  while (ptr < endptr)
1085    /* At this point, ptr is at the start of a line. We need to find the length    /* At this point, ptr is at the start of a line. We need to find the length
1086    of the subject string to pass to pcre_exec(). In multiline mode, it is the    of the subject string to pass to pcre_exec(). In multiline mode, it is the
1087    length remainder of the data in the buffer. Otherwise, it is the length of    length remainder of the data in the buffer. Otherwise, it is the length of
1088    the next line. After matching, we always advance by the length of the next    the next line, excluding the terminating newline. After matching, we always
1089    line. In multiline mode the PCRE_FIRSTLINE option is used for compiling, so    advance by the length of the next line. In multiline mode the PCRE_FIRSTLINE
1090    that any match is constrained to be in the first line. */    option is used for compiling, so that any match is constrained to be in the
1091      first line. */
1092    
1093    t = end_of_line(t, endptr, &endlinelength);    t = end_of_line(t, endptr, &endlinelength);
1094    linelength = t - ptr - endlinelength;    linelength = t - ptr - endlinelength;
# Line 936  while (ptr < endptr) Line 1103  while (ptr < endptr)
1103        #include <time.h>        #include <time.h>
1104        struct timeval start_time, end_time;        struct timeval start_time, end_time;
1105        struct timezone dummy;        struct timezone dummy;
1106          int i;
1107    
1108        if (jfriedl_XT)        if (jfriedl_XT)
1109        {        {
# Line 944  while (ptr < endptr) Line 1112  while (ptr < endptr)
1112            ptr = malloc(newlen + 1);            ptr = malloc(newlen + 1);
1113            if (!ptr) {            if (!ptr) {
1114                    printf("out of memory");                    printf("out of memory");
1115                    exit(2);                    pcregrep_exit(2);
1116            }            }
1117            endptr = ptr;            endptr = ptr;
1118            strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);            strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);
# Line 961  while (ptr < endptr) Line 1129  while (ptr < endptr)
1129    
1130    
1131        for (i = 0; i < jfriedl_XR; i++)        for (i = 0; i < jfriedl_XR; i++)
1132            match = (pcre_exec(pattern_list[0], hints_list[0], ptr, length, 0, 0, offsets, 99) >= 0);            match = (pcre_exec(pattern_list[0], hints_list[0], ptr, length, 0,
1133                  PCRE_NOTEMPTY, offsets, OFFSET_SIZE) >= 0);
1134    
1135        if (gettimeofday(&end_time, &dummy) != 0)        if (gettimeofday(&end_time, &dummy) != 0)
1136                perror("bad gettimeofday");                perror("bad gettimeofday");
# Line 980  while (ptr < endptr) Line 1149  while (ptr < endptr)
1149    
1150    ONLY_MATCHING_RESTART:    ONLY_MATCHING_RESTART:
1151    
1152    /* Run through all the patterns until one matches. Note that we don't include    /* Run through all the patterns until one matches or there is an error other
1153    the final newline in the subject string. */    than NOMATCH. This code is in a subroutine so that it can be re-used for
1154      finding subsequent matches when colouring matched lines. */
1155    
1156    for (i = 0; i < pattern_count; i++)    match = match_patterns(matchptr, length, offsets, &mrc);
     {  
     mrc = pcre_exec(pattern_list[i], hints_list[i], matchptr, length, 0, 0,  
       offsets, 99);  
     if (mrc >= 0) { match = TRUE; break; }  
     if (mrc != PCRE_ERROR_NOMATCH)  
       {  
       fprintf(stderr, "pcregrep: pcre_exec() error %d while matching ", mrc);  
       if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);  
       fprintf(stderr, "this line:\n");  
       fwrite(matchptr, 1, linelength, stderr);  /* In case binary zero included */  
       fprintf(stderr, "\n");  
       if (error_count == 0 &&  
           (mrc == PCRE_ERROR_MATCHLIMIT || mrc == PCRE_ERROR_RECURSIONLIMIT))  
         {  
         fprintf(stderr, "pcregrep: error %d means that a resource limit "  
           "was exceeded\n", mrc);  
         fprintf(stderr, "pcregrep: check your regex for nested unlimited loops\n");  
         }  
       if (error_count++ > 20)  
         {  
         fprintf(stderr, "pcregrep: too many errors - abandoned\n");  
         exit(2);  
         }  
       match = invert;    /* No more matching; don't show the line again */  
       break;  
       }  
     }  
1157    
1158    /* If it's a match or a not-match (as required), do what's wanted. */    /* If it's a match or a not-match (as required), do what's wanted. */
1159    
# Line 1029  while (ptr < endptr) Line 1172  while (ptr < endptr)
1172      /* If all we want is a file name, there is no need to scan any more lines      /* If all we want is a file name, there is no need to scan any more lines
1173      in the file. */      in the file. */
1174    
1175      else if (filenames == FN_ONLY)      else if (filenames == FN_MATCH_ONLY)
1176        {        {
1177        fprintf(stdout, "%s\n", printname);        fprintf(stdout, "%s\n", printname);
1178        return 0;        return 0;
# Line 1039  while (ptr < endptr) Line 1182  while (ptr < endptr)
1182    
1183      else if (quiet) return 0;      else if (quiet) return 0;
1184    
1185      /* The --only-matching option prints just the substring that matched, and      /* The --only-matching option prints just the substring that matched, or a
1186      the --file-offsets and --line-offsets options output offsets for the      captured portion of it, as long as this string is not empty, and the
1187      matching substring (they both force --only-matching). None of these options      --file-offsets and --line-offsets options output offsets for the matching
1188        substring (they both force --only-matching = 0). None of these options
1189      prints any context. Afterwards, adjust the start and length, and then jump      prints any context. Afterwards, adjust the start and length, and then jump
1190      back to look for further matches in the same line. If we are in invert      back to look for further matches in the same line. If we are in invert
1191      mode, however, nothing is printed - this could be still useful because the      mode, however, nothing is printed and we do not restart - this could still
1192      return code is set. */      be useful because the return code is set. */
1193    
1194      else if (only_matching)      else if (only_matching >= 0)
1195        {        {
1196        if (!invert)        if (!invert)
1197          {          {
1198          if (printname != NULL) fprintf(stdout, "%s:", printname);          if (printname != NULL) fprintf(stdout, "%s:", printname);
1199          if (number) fprintf(stdout, "%d:", linenumber);          if (number) fprintf(stdout, "%d:", linenumber);
1200          if (line_offsets)          if (line_offsets)
1201            fprintf(stdout, "%d,%d", matchptr + offsets[0] - ptr,            fprintf(stdout, "%d,%d\n", (int)(matchptr + offsets[0] - ptr),
1202              offsets[1] - offsets[0]);              offsets[1] - offsets[0]);
1203          else if (file_offsets)          else if (file_offsets)
1204            fprintf(stdout, "%d,%d", filepos + matchptr + offsets[0] - ptr,            fprintf(stdout, "%d,%d\n",
1205                (int)(filepos + matchptr + offsets[0] - ptr),
1206              offsets[1] - offsets[0]);              offsets[1] - offsets[0]);
1207          else          else if (only_matching < mrc)
1208            fwrite(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);            {
1209          fprintf(stdout, "\n");            int plen = offsets[2*only_matching + 1] - offsets[2*only_matching];
1210              if (plen > 0)
1211                {
1212                if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1213                FWRITE(matchptr + offsets[only_matching*2], 1, plen, stdout);
1214                if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
1215                fprintf(stdout, "\n");
1216                }
1217              }
1218            else if (printname != NULL || number) fprintf(stdout, "\n");
1219          matchptr += offsets[1];          matchptr += offsets[1];
1220          length -= offsets[1];          length -= offsets[1];
1221          match = FALSE;          match = FALSE;
1222            if (line_buffered) fflush(stdout);
1223            rc = 0;    /* Had some success */
1224          goto ONLY_MATCHING_RESTART;          goto ONLY_MATCHING_RESTART;
1225          }          }
1226        }        }
# Line 1100  while (ptr < endptr) Line 1256  while (ptr < endptr)
1256            if (printname != NULL) fprintf(stdout, "%s-", printname);            if (printname != NULL) fprintf(stdout, "%s-", printname);
1257            if (number) fprintf(stdout, "%d-", lastmatchnumber++);            if (number) fprintf(stdout, "%d-", lastmatchnumber++);
1258            pp = end_of_line(pp, endptr, &ellength);            pp = end_of_line(pp, endptr, &ellength);
1259            fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout);            FWRITE(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
1260            lastmatchrestart = pp;            lastmatchrestart = pp;
1261            }            }
1262          if (lastmatchrestart != ptr) hyphenpending = TRUE;          if (lastmatchrestart != ptr) hyphenpending = TRUE;
# Line 1140  while (ptr < endptr) Line 1296  while (ptr < endptr)
1296            if (printname != NULL) fprintf(stdout, "%s-", printname);            if (printname != NULL) fprintf(stdout, "%s-", printname);
1297            if (number) fprintf(stdout, "%d-", linenumber - linecount--);            if (number) fprintf(stdout, "%d-", linenumber - linecount--);
1298            pp = end_of_line(pp, endptr, &ellength);            pp = end_of_line(pp, endptr, &ellength);
1299            fwrite(p, 1, pp - p, stdout);            FWRITE(p, 1, pp - p, stdout);
1300            p = pp;            p = pp;
1301            }            }
1302          }          }
# Line 1160  while (ptr < endptr) Line 1316  while (ptr < endptr)
1316        (invert not set). Because the PCRE_FIRSTLINE option is set, the start of        (invert not set). Because the PCRE_FIRSTLINE option is set, the start of
1317        the match will always be before the first newline sequence. */        the match will always be before the first newline sequence. */
1318    
1319        if (multiline)        if (multiline & !invert)
1320          {          {
1321          int ellength;          char *endmatch = ptr + offsets[1];
1322          char *endmatch = ptr;          t = ptr;
1323          if (!invert)          while (t < endmatch)
1324            {            {
1325            endmatch += offsets[1];            t = end_of_line(t, endptr, &endlinelength);
1326            t = ptr;            if (t < endmatch) linenumber++; else break;
           while (t < endmatch)  
             {  
             t = end_of_line(t, endptr, &ellength);  
             if (t <= endmatch) linenumber++; else break;  
             }  
1327            }            }
1328          endmatch = end_of_line(endmatch, endptr, &ellength);          linelength = t - ptr - endlinelength;
         linelength = endmatch - ptr - ellength;  
1329          }          }
1330    
1331        /*** NOTE: Use only fwrite() to output the data line, so that binary        /*** NOTE: Use only fwrite() to output the data line, so that binary
# Line 1190  while (ptr < endptr) Line 1340  while (ptr < endptr)
1340          {          {
1341          int first = S_arg * 2;          int first = S_arg * 2;
1342          int last  = first + 1;          int last  = first + 1;
1343          fwrite(ptr, 1, offsets[first], stdout);          FWRITE(ptr, 1, offsets[first], stdout);
1344          fprintf(stdout, "X");          fprintf(stdout, "X");
1345          fwrite(ptr + offsets[last], 1, linelength - offsets[last], stdout);          FWRITE(ptr + offsets[last], 1, linelength - offsets[last], stdout);
1346          }          }
1347        else        else
1348  #endif  #endif
1349    
1350        /* We have to split the line(s) up if colouring. */        /* We have to split the line(s) up if colouring, and search for further
1351          matches, but not of course if the line is a non-match. */
1352    
1353        if (do_colour)        if (do_colour && !invert)
1354          {          {
1355          fwrite(ptr, 1, offsets[0], stdout);          int plength;
1356            int last_offset = 0;
1357            FWRITE(ptr, 1, offsets[0], stdout);
1358          fprintf(stdout, "%c[%sm", 0x1b, colour_string);          fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1359          fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);          FWRITE(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1360          fprintf(stdout, "%c[00m", 0x1b);          fprintf(stdout, "%c[00m", 0x1b);
1361          fwrite(ptr + offsets[1], 1, (linelength + endlinelength) - offsets[1],          for (;;)
1362            stdout);            {
1363              last_offset += offsets[1];
1364              matchptr += offsets[1];
1365              length -= offsets[1];
1366              if (last_offset >= linelength + endlinelength ||
1367                  !match_patterns(matchptr, length, offsets, &mrc)) break;
1368              FWRITE(matchptr, 1, offsets[0], stdout);
1369              fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1370              FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1371              fprintf(stdout, "%c[00m", 0x1b);
1372              }
1373    
1374            /* In multiline mode, we may have already printed the complete line
1375            and its line-ending characters (if they matched the pattern), so there
1376            may be no more to print. */
1377    
1378            plength = (linelength + endlinelength) - last_offset;
1379            if (plength > 0)
1380              FWRITE(ptr + last_offset, 1, plength, stdout);
1381          }          }
1382        else fwrite(ptr, 1, linelength + endlinelength, stdout);  
1383          /* Not colouring; no need to search for further matches */
1384    
1385          else FWRITE(ptr, 1, linelength + endlinelength, stdout);
1386        }        }
1387    
1388      /* End of doing what has to be done for a match */      /* End of doing what has to be done for a match. If --line-buffered was
1389        given, flush the output. */
1390    
1391        if (line_buffered) fflush(stdout);
1392      rc = 0;    /* Had some success */      rc = 0;    /* Had some success */
1393    
1394      /* Remember where the last match happened for after_context. We remember      /* Remember where the last match happened for after_context. We remember
# Line 1244  while (ptr < endptr) Line 1420  while (ptr < endptr)
1420    offset to the current line is maintained in filepos. */    offset to the current line is maintained in filepos. */
1421    
1422    ptr += linelength + endlinelength;    ptr += linelength + endlinelength;
1423    filepos += linelength + endlinelength;    filepos += (int)(linelength + endlinelength);
1424    linenumber++;    linenumber++;
1425    
1426      /* If input is line buffered, and the buffer is not yet full, read another
1427      line and add it into the buffer. */
1428    
1429      if (input_line_buffered && bufflength < sizeof(buffer))
1430        {
1431        int add = read_one_line(ptr, sizeof(buffer) - (ptr - buffer), in);
1432        bufflength += add;
1433        endptr += add;
1434        }
1435    
1436    /* 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
1437    the current point is in the top 1/3 of the buffer, slide the buffer down by    the current point is in the top 1/3 of the buffer, slide the buffer down by
1438    1/3 and refill it. Before we do this, if some unprinted "after" lines are    1/3 and refill it. Before we do this, if some unprinted "after" lines are
# Line 1281  while (ptr < endptr) Line 1467  while (ptr < endptr)
1467      else      else
1468  #endif  #endif
1469    
1470      bufflength = 2*MBUFTHIRD + fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in);      bufflength = 2*MBUFTHIRD +
1471          (input_line_buffered?
1472           read_one_line(buffer + 2*MBUFTHIRD, MBUFTHIRD, in) :
1473           fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in));
1474      endptr = buffer + bufflength;      endptr = buffer + bufflength;
1475    
1476      /* Adjust any last match point */      /* Adjust any last match point */
# Line 1294  while (ptr < endptr) Line 1482  while (ptr < endptr)
1482  /* End of file; print final "after" lines if wanted; do_after_lines sets  /* End of file; print final "after" lines if wanted; do_after_lines sets
1483  hyphenpending if it prints something. */  hyphenpending if it prints something. */
1484    
1485  if (!only_matching && !count_only)  if (only_matching < 0 && !count_only)
1486    {    {
1487    do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);    do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
1488    hyphenpending |= endhyphenpending;    hyphenpending |= endhyphenpending;
# Line 1313  if (filenames == FN_NOMATCH_ONLY) Line 1501  if (filenames == FN_NOMATCH_ONLY)
1501    
1502  if (count_only)  if (count_only)
1503    {    {
1504    if (printname != NULL) fprintf(stdout, "%s:", printname);    if (count > 0 || !omit_zero_count)
1505    fprintf(stdout, "%d\n", count);      {
1506        if (printname != NULL && filenames != FN_NONE)
1507          fprintf(stdout, "%s:", printname);
1508        fprintf(stdout, "%d\n", count);
1509        }
1510    }    }
1511    
1512  return rc;  return rc;
# Line 1394  if ((sep = isdirectory(pathname)) != 0) Line 1586  if ((sep = isdirectory(pathname)) != 0)
1586        {        {
1587        int frc, nflen;        int frc, nflen;
1588        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);
1589        nflen = strlen(nextfile);        nflen = (int)(strlen(nextfile));
1590    
1591        if (isdirectory(buffer))        if (isdirectory(buffer))
1592          {          {
# Line 1438  skipping was not requested. The scan pro Line 1630  skipping was not requested. The scan pro
1630  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
1631  the file name, or the filename was forced (-H). */  the file name, or the filename was forced (-H). */
1632    
1633  pathlen = strlen(pathname);  pathlen = (int)(strlen(pathname));
1634    
1635  /* Open using zlib if it is supported and the file name ends with .gz. */  /* Open using zlib if it is supported and the file name ends with .gz. */
1636    
# Line 1478  an attempt to read a .bz2 file indicates Line 1670  an attempt to read a .bz2 file indicates
1670  PLAIN_FILE:  PLAIN_FILE:
1671  #endif  #endif
1672    {    {
1673    in = fopen(pathname, "r");    in = fopen(pathname, "rb");
1674    handle = (void *)in;    handle = (void *)in;
1675    frtype = FR_PLAIN;    frtype = FR_PLAIN;
1676    }    }
# Line 1600  for (op = optionlist; op->one_char != 0; Line 1792  for (op = optionlist; op->one_char != 0;
1792    {    {
1793    int n;    int n;
1794    char s[4];    char s[4];
1795    
1796      /* Two options were accidentally implemented and documented with underscores
1797      instead of hyphens in their names, something that was not noticed for quite a
1798      few releases. When fixing this, I left the underscored versions in the list
1799      in case people were using them. However, we don't want to display them in the
1800      help data. There are no other options that contain underscores, and we do not
1801      expect ever to implement such options. Therefore, just omit any option that
1802      contains an underscore. */
1803    
1804      if (strchr(op->long_name, '_') != NULL) continue;
1805    
1806    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, "   ");
1807    n = 30 - printf("  %s --%s", s, op->long_name);    n = 31 - printf("  %s --%s", s, op->long_name);
1808    if (n < 1) n = 1;    if (n < 1) n = 1;
1809    printf("%.*s%s\n", n, "                    ", op->help_text);    printf("%.*s%s\n", n, "                     ", op->help_text);
1810    }    }
1811    
1812  printf("\nWhen reading patterns from a file instead of using a command line option,\n");  printf("\nWhen reading patterns from a file instead of using a command line option,\n");
# Line 1627  handle_option(int letter, int options) Line 1830  handle_option(int letter, int options)
1830  switch(letter)  switch(letter)
1831    {    {
1832    case N_FOFFSETS: file_offsets = TRUE; break;    case N_FOFFSETS: file_offsets = TRUE; break;
1833    case N_HELP: help(); exit(0);    case N_HELP: help(); pcregrep_exit(0);
1834    case N_LOFFSETS: line_offsets = number = TRUE; break;    case N_LOFFSETS: line_offsets = number = TRUE; break;
1835      case N_LBUFFER: line_buffered = TRUE; break;
1836    case 'c': count_only = TRUE; break;    case 'c': count_only = TRUE; break;
1837    case 'F': process_options |= PO_FIXED_STRINGS; break;    case 'F': process_options |= PO_FIXED_STRINGS; break;
1838    case 'H': filenames = FN_FORCE; break;    case 'H': filenames = FN_FORCE; break;
1839    case 'h': filenames = FN_NONE; break;    case 'h': filenames = FN_NONE; break;
1840    case 'i': options |= PCRE_CASELESS; break;    case 'i': options |= PCRE_CASELESS; break;
1841    case 'l': filenames = FN_ONLY; break;    case 'l': omit_zero_count = TRUE; filenames = FN_MATCH_ONLY; break;
1842    case 'L': filenames = FN_NOMATCH_ONLY; break;    case 'L': filenames = FN_NOMATCH_ONLY; break;
1843    case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;    case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;
1844    case 'n': number = TRUE; break;    case 'n': number = TRUE; break;
1845    case 'o': only_matching = TRUE; break;    case 'o': only_matching = 0; break;
1846    case 'q': quiet = TRUE; break;    case 'q': quiet = TRUE; break;
1847    case 'r': dee_action = dee_RECURSE; break;    case 'r': dee_action = dee_RECURSE; break;
1848    case 's': silent = TRUE; break;    case 's': silent = TRUE; break;
# Line 1649  switch(letter) Line 1853  switch(letter)
1853    
1854    case 'V':    case 'V':
1855    fprintf(stderr, "pcregrep version %s\n", pcre_version());    fprintf(stderr, "pcregrep version %s\n", pcre_version());
1856    exit(0);    pcregrep_exit(0);
1857    break;    break;
1858    
1859    default:    default:
1860    fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);    fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);
1861    exit(usage(2));    pcregrep_exit(usage(2));
1862    }    }
1863    
1864  return options;  return options;
# Line 1819  const char *error; Line 2023  const char *error;
2023    
2024  /* Set the default line ending value from the default in the PCRE library;  /* Set the default line ending value from the default in the PCRE library;
2025  "lf", "cr", "crlf", and "any" are supported. Anything else is treated as "lf".  "lf", "cr", "crlf", and "any" are supported. Anything else is treated as "lf".
2026  */  Note that the return values from pcre_config(), though derived from the ASCII
2027    codes, are the same in EBCDIC environments, so we must use the actual values
2028    rather than escapes such as as '\r'. */
2029    
2030  (void)pcre_config(PCRE_CONFIG_NEWLINE, &i);  (void)pcre_config(PCRE_CONFIG_NEWLINE, &i);
2031  switch(i)  switch(i)
2032    {    {
2033    default:                 newline = (char *)"lf"; break;    default:               newline = (char *)"lf"; break;
2034    case '\r':               newline = (char *)"cr"; break;    case 13:               newline = (char *)"cr"; break;
2035    case ('\r' << 8) | '\n': newline = (char *)"crlf"; break;    case (13 << 8) | 10:   newline = (char *)"crlf"; break;
2036    case -1:                 newline = (char *)"any"; break;    case -1:               newline = (char *)"any"; break;
2037    case -2:                 newline = (char *)"anycrlf"; break;    case -2:               newline = (char *)"anycrlf"; break;
2038    }    }
2039    
2040  /* Process the options */  /* Process the options */
# Line 1848  for (i = 1; i < argc; i++) Line 2054  for (i = 1; i < argc; i++)
2054    if (argv[i][1] == 0)    if (argv[i][1] == 0)
2055      {      {
2056      if (pattern_filename != NULL || pattern_count > 0) break;      if (pattern_filename != NULL || pattern_count > 0) break;
2057        else exit(usage(2));        else pcregrep_exit(usage(2));
2058      }      }
2059    
2060    /* Handle a long name option, or -- to terminate the options */    /* Handle a long name option, or -- to terminate the options */
# Line 1870  for (i = 1; i < argc; i++) Line 2076  for (i = 1; i < argc; i++)
2076      Some options have variations in the long name spelling: specifically, we      Some options have variations in the long name spelling: specifically, we
2077      allow "regexp" because GNU grep allows it, though I personally go along      allow "regexp" because GNU grep allows it, though I personally go along
2078      with Jeffrey Friedl and Larry Wall in preferring "regex" without the "p".      with Jeffrey Friedl and Larry Wall in preferring "regex" without the "p".
2079      These options are entered in the table as "regex(p)". No option is in both      These options are entered in the table as "regex(p)". Options can be in
2080      these categories, fortunately. */      both these categories. */
2081    
2082      for (op = optionlist; op->one_char != 0; op++)      for (op = optionlist; op->one_char != 0; op++)
2083        {        {
2084        char *opbra = strchr(op->long_name, '(');        char *opbra = strchr(op->long_name, '(');
2085        char *equals = strchr(op->long_name, '=');        char *equals = strchr(op->long_name, '=');
2086        if (opbra == NULL)     /* Not a (p) case */  
2087          /* Handle options with only one spelling of the name */
2088    
2089          if (opbra == NULL)     /* Does not contain '(' */
2090          {          {
2091          if (equals == NULL)  /* Not thing=data case */          if (equals == NULL)  /* Not thing=data case */
2092            {            {
# Line 1885  for (i = 1; i < argc; i++) Line 2094  for (i = 1; i < argc; i++)
2094            }            }
2095          else                 /* Special case xxx=data */          else                 /* Special case xxx=data */
2096            {            {
2097            int oplen = equals - op->long_name;            int oplen = (int)(equals - op->long_name);
2098            int arglen = (argequals == NULL)? (int)strlen(arg) : argequals - arg;            int arglen = (argequals == NULL)?
2099                (int)strlen(arg) : (int)(argequals - arg);
2100            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)
2101              {              {
2102              option_data = arg + arglen;              option_data = arg + arglen;
# Line 1899  for (i = 1; i < argc; i++) Line 2109  for (i = 1; i < argc; i++)
2109              }              }
2110            }            }
2111          }          }
2112        else                   /* Special case xxxx(p) */  
2113          /* Handle options with an alternate spelling of the name */
2114    
2115          else
2116          {          {
2117          char buff1[24];          char buff1[24];
2118          char buff2[24];          char buff2[24];
2119          int baselen = opbra - op->long_name;  
2120            int baselen = (int)(opbra - op->long_name);
2121            int fulllen = (int)(strchr(op->long_name, ')') - op->long_name + 1);
2122            int arglen = (argequals == NULL || equals == NULL)?
2123              (int)strlen(arg) : (int)(argequals - arg);
2124    
2125          sprintf(buff1, "%.*s", baselen, op->long_name);          sprintf(buff1, "%.*s", baselen, op->long_name);
2126          sprintf(buff2, "%s%.*s", buff1,          sprintf(buff2, "%s%.*s", buff1, fulllen - baselen - 2, opbra + 1);
2127            (int)strlen(op->long_name) - baselen - 2, opbra + 1);  
2128          if (strcmp(arg, buff1) == 0 || strcmp(arg, buff2) == 0)          if (strncmp(arg, buff1, arglen) == 0 ||
2129               strncmp(arg, buff2, arglen) == 0)
2130              {
2131              if (equals != NULL && argequals != NULL)
2132                {
2133                option_data = argequals;
2134                if (*option_data == '=')
2135                  {
2136                  option_data++;
2137                  longopwasequals = TRUE;
2138                  }
2139                }
2140            break;            break;
2141              }
2142          }          }
2143        }        }
2144    
2145      if (op->one_char == 0)      if (op->one_char == 0)
2146        {        {
2147        fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);        fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);
2148        exit(usage(2));        pcregrep_exit(usage(2));
2149        }        }
2150      }      }
2151    
   
2152    /* Jeffrey Friedl's debugging harness uses these additional options which    /* Jeffrey Friedl's debugging harness uses these additional options which
2153    are not in the right form for putting in the option table because they use    are not in the right form for putting in the option table because they use
2154    only one hyphen, yet are more than one character long. By putting them    only one hyphen, yet are more than one character long. By putting them
# Line 1953  for (i = 1; i < argc; i++) Line 2182  for (i = 1; i < argc; i++)
2182      while (*s != 0)      while (*s != 0)
2183        {        {
2184        for (op = optionlist; op->one_char != 0; op++)        for (op = optionlist; op->one_char != 0; op++)
2185          { if (*s == op->one_char) break; }          {
2186            if (*s == op->one_char) break;
2187            }
2188        if (op->one_char == 0)        if (op->one_char == 0)
2189          {          {
2190          fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",          fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",
2191            *s, argv[i]);            *s, argv[i]);
2192          exit(usage(2));          pcregrep_exit(usage(2));
2193            }
2194    
2195          /* Check for a single-character option that has data: OP_OP_NUMBER
2196          is used for one that either has a numerical number or defaults, i.e. the
2197          data is optional. If a digit follows, there is data; if not, carry on
2198          with other single-character options in the same string. */
2199    
2200          option_data = s+1;
2201          if (op->type == OP_OP_NUMBER)
2202            {
2203            if (isdigit((unsigned char)s[1])) break;
2204          }          }
2205        if (op->type != OP_NODATA || s[1] == 0)        else   /* Check for end or a dataless option */
2206          {          {
2207          option_data = s+1;          if (op->type != OP_NODATA || s[1] == 0) break;
         break;  
2208          }          }
2209    
2210          /* Handle a single-character option with no data, then loop for the
2211          next character in the string. */
2212    
2213        pcre_options = handle_option(*s++, pcre_options);        pcre_options = handle_option(*s++, pcre_options);
2214        }        }
2215      }      }
# Line 1981  for (i = 1; i < argc; i++) Line 2226  for (i = 1; i < argc; i++)
2226    
2227    /* If the option type is OP_OP_STRING or OP_OP_NUMBER, it's an option that    /* If the option type is OP_OP_STRING or OP_OP_NUMBER, it's an option that
2228    either has a value or defaults to something. It cannot have data in a    either has a value or defaults to something. It cannot have data in a
2229    separate item. At the moment, the only such options are "colo(u)r" and    separate item. At the moment, the only such options are "colo(u)r",
2230    Jeffrey Friedl's special -S debugging option. */    "only-matching", and Jeffrey Friedl's special -S debugging option. */
2231    
2232    if (*option_data == 0 &&    if (*option_data == 0 &&
2233        (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))        (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))
# Line 1992  for (i = 1; i < argc; i++) Line 2237  for (i = 1; i < argc; i++)
2237        case N_COLOUR:        case N_COLOUR:
2238        colour_option = (char *)"auto";        colour_option = (char *)"auto";
2239        break;        break;
2240    
2241          case 'o':
2242          only_matching = 0;
2243          break;
2244    
2245  #ifdef JFRIEDL_DEBUG  #ifdef JFRIEDL_DEBUG
2246        case 'S':        case 'S':
2247        S_arg = 0;        S_arg = 0;
# Line 2008  for (i = 1; i < argc; i++) Line 2258  for (i = 1; i < argc; i++)
2258      if (i >= argc - 1 || longopwasequals)      if (i >= argc - 1 || longopwasequals)
2259        {        {
2260        fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);        fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);
2261        exit(usage(2));        pcregrep_exit(usage(2));
2262        }        }
2263      option_data = argv[++i];      option_data = argv[++i];
2264      }      }
# Line 2029  for (i = 1; i < argc; i++) Line 2279  for (i = 1; i < argc; i++)
2279    
2280    /* Otherwise, deal with single string or numeric data values. */    /* Otherwise, deal with single string or numeric data values. */
2281    
2282    else if (op->type != OP_NUMBER && op->type != OP_OP_NUMBER)    else if (op->type != OP_NUMBER && op->type != OP_LONGNUMBER &&
2283               op->type != OP_OP_NUMBER)
2284      {      {
2285      *((char **)op->dataptr) = option_data;      *((char **)op->dataptr) = option_data;
2286      }      }
2287    
2288      /* Avoid the use of strtoul() because SunOS4 doesn't have it. This is used
2289      only for unpicking arguments, so just keep it simple. */
2290    
2291    else    else
2292      {      {
2293      char *endptr;      unsigned long int n = 0;
2294      int n = strtoul(option_data, &endptr, 10);      char *endptr = option_data;
2295        while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++;
2296        while (isdigit((unsigned char)(*endptr)))
2297          n = n * 10 + (int)(*endptr++ - '0');
2298      if (*endptr != 0)      if (*endptr != 0)
2299        {        {
2300        if (longop)        if (longop)
2301          {          {
2302          char *equals = strchr(op->long_name, '=');          char *equals = strchr(op->long_name, '=');
2303          int nlen = (equals == NULL)? (int)strlen(op->long_name) :          int nlen = (equals == NULL)? (int)strlen(op->long_name) :
2304            equals - op->long_name;            (int)(equals - op->long_name);
2305          fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",          fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",
2306            option_data, nlen, op->long_name);            option_data, nlen, op->long_name);
2307          }          }
2308        else        else
2309          fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",          fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",
2310            option_data, op->one_char);            option_data, op->one_char);
2311        exit(usage(2));        pcregrep_exit(usage(2));
2312        }        }
2313      *((int *)op->dataptr) = n;      if (op->type == OP_LONGNUMBER)
2314            *((unsigned long int *)op->dataptr) = n;
2315        else
2316            *((int *)op->dataptr) = n;
2317      }      }
2318    }    }
2319    
# Line 2066  if (both_context > 0) Line 2327  if (both_context > 0)
2327    }    }
2328    
2329  /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.  /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.
2330  However, the latter two set the only_matching flag. */  However, the latter two set only_matching. */
2331    
2332  if ((only_matching && (file_offsets || line_offsets)) ||  if ((only_matching >= 0 && (file_offsets || line_offsets)) ||
2333      (file_offsets && line_offsets))      (file_offsets && line_offsets))
2334    {    {
2335    fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "    fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "
2336      "and/or --line-offsets\n");      "and/or --line-offsets\n");
2337    exit(usage(2));    pcregrep_exit(usage(2));
2338    }    }
2339    
2340  if (file_offsets || line_offsets) only_matching = TRUE;  if (file_offsets || line_offsets) only_matching = 0;
2341    
2342  /* 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
2343  LC_ALL environment variable is set, and if so, use it. */  LC_ALL environment variable is set, and if so, use it. */
# Line 2285  for (j = 0; j < pattern_count; j++) Line 2546  for (j = 0; j < pattern_count; j++)
2546    hint_count++;    hint_count++;
2547    }    }
2548    
2549    /* If --match-limit or --recursion-limit was set, put the value(s) into the
2550    pcre_extra block for each pattern. */
2551    
2552    if (match_limit > 0 || match_limit_recursion > 0)
2553      {
2554      for (j = 0; j < pattern_count; j++)
2555        {
2556        if (hints_list[j] == NULL)
2557          {
2558          hints_list[j] = malloc(sizeof(pcre_extra));
2559          if (hints_list[j] == NULL)
2560            {
2561            fprintf(stderr, "pcregrep: malloc failed\n");
2562            pcregrep_exit(2);
2563            }
2564          }
2565        if (match_limit > 0)
2566          {
2567          hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT;
2568          hints_list[j]->match_limit = match_limit;
2569          }
2570        if (match_limit_recursion > 0)
2571          {
2572          hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
2573          hints_list[j]->match_limit_recursion = match_limit_recursion;
2574          }
2575        }
2576      }
2577    
2578  /* If there are include or exclude patterns, compile them. */  /* If there are include or exclude patterns, compile them. */
2579    
2580  if (exclude_pattern != NULL)  if (exclude_pattern != NULL)
# Line 2366  if (pattern_list != NULL) Line 2656  if (pattern_list != NULL)
2656    }    }
2657  if (hints_list != NULL)  if (hints_list != NULL)
2658    {    {
2659    for (i = 0; i < hint_count; i++) free(hints_list[i]);    for (i = 0; i < hint_count; i++)
2660        {
2661        if (hints_list[i] != NULL) free(hints_list[i]);
2662        }
2663    free(hints_list);    free(hints_list);
2664    }    }
2665  return rc;  pcregrep_exit(rc);
2666    
2667  EXIT2:  EXIT2:
2668  rc = 2;  rc = 2;

Legend:
Removed from v.345  
changed lines
  Added in v.589

  ViewVC Help
Powered by ViewVC 1.1.5