/[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 461 by ph10, Mon Oct 5 10:59:35 2009 UTC revision 571 by ph10, Tue Nov 16 17:51:37 2010 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-2009 University of Cambridge             Copyright (c) 1997-2010 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 104  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 155  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 omit_zero_count = FALSE;  static BOOL omit_zero_count = FALSE;
182  static BOOL only_matching = FALSE;  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;
# Line 198  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" },
# Line 205  static option_item optionlist[] = { Line 221  static option_item optionlist[] = {
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_OP_STRING, N_COLOUR, &colour_option,    "colour=option", "matched text colour option" },
225    { OP_NUMBER,    'C',      &both_context,     "context=number", "set number of context lines, before & after" },    { OP_NUMBER,    'C',      &both_context,     "context=number", "set number of context lines, before & after" },
226    { OP_NODATA,    'c',      NULL,              "count",         "print only a count of matching lines per FILE" },    { OP_NODATA,    'c',      NULL,              "count",         "print only a count of matching lines per FILE" },
   { OP_OP_STRING, N_COLOUR, &colour_option,    "colour=option", "matched text colour option" },  
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)=pattern", "specify pattern (may be used more than once)" },    { OP_PATLIST,   'e',      NULL,              "regex(p)=pattern", "specify pattern (may be used more than once)" },
# Line 220  static option_item optionlist[] = { Line 236  static option_item optionlist[] = {
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_LBUFFER, NULL,             "line-buffered", "use line buffering" },
240    { OP_NODATA,    N_LOFFSETS, NULL,            "line-offsets",  "output line numbers and offsets, not text" },    { OP_NODATA,    N_LOFFSETS, NULL,            "line-offsets",  "output line numbers and offsets, not text" },
241    { OP_STRING,    N_LOCALE, &locale,           "locale=locale", "use the named locale" },    { OP_STRING,    N_LOCALE, &locale,           "locale=locale", "use the named locale" },
242      { OP_NUMBER,    N_M_LIMIT,&match_limit,      "match-limit=number", "set PCRE match limit option" },
243      { OP_NUMBER,    N_M_LIMIT_REC,&match_limit_recursion, "recursion-limit=number", "set PCRE match recursion limit option" },
244    { OP_NODATA,    'M',      NULL,              "multiline",     "run in multiline mode" },    { OP_NODATA,    'M',      NULL,              "multiline",     "run in multiline mode" },
245    { OP_STRING,    'N',      &newline,          "newline=type",  "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" },    { OP_STRING,    'N',      &newline,          "newline=type",  "set newline type (CR, LF, CRLF, ANYCRLF or ANY)" },
246    { OP_NODATA,    'n',      NULL,              "line-number",   "print line number with output lines" },    { OP_NODATA,    'n',      NULL,              "line-number",   "print line number with output lines" },
247    { OP_NODATA,    'o',      NULL,              "only-matching", "show only the part of the line that matched" },    { OP_OP_NUMBER, 'o',      &only_matching,    "only-matching=n", "show only the part of the line that matched" },
248    { OP_NODATA,    'q',      NULL,              "quiet",         "suppress output, just set return code" },    { OP_NODATA,    'q',      NULL,              "quiet",         "suppress output, just set return code" },
249    { OP_NODATA,    'r',      NULL,              "recursive",     "recursively scan sub-directories" },    { OP_NODATA,    'r',      NULL,              "recursive",     "recursively scan sub-directories" },
250    { 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" },
251    { 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" },
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 331  return (statbuf.st_mode & S_IFMT) == S_I Line 359  return (statbuf.st_mode & S_IFMT) == S_I
359  }  }
360    
361    
362  /************* Test stdout for being a terminal in Unix **********/  /************* Test for a terminal in Unix **********/
363    
364  static BOOL  static BOOL
365  is_stdout_tty(void)  is_stdout_tty(void)
# Line 339  is_stdout_tty(void) Line 367  is_stdout_tty(void)
367  return isatty(fileno(stdout));  return isatty(fileno(stdout));
368  }  }
369    
370    static BOOL
371    is_file_tty(FILE *f)
372    {
373    return isatty(fileno(f));
374    }
375    
376    
377  /************* Directory scanning in Win32 ***********/  /************* Directory scanning in Win32 ***********/
378    
# Line 346  return isatty(fileno(stdout)); Line 380  return isatty(fileno(stdout));
380  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES
381  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
382  <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.  <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.
383  */  The double test below stops gcc 4.4.4 grumbling that HAVE_WINDOWS_H is
384    undefined when it is indeed undefined. */
385    
386  #elif HAVE_WINDOWS_H  #elif defined HAVE_WINDOWS_H && HAVE_WINDOWS_H
387    
388  #ifndef STRICT  #ifndef STRICT
389  # define STRICT  # define STRICT
# Line 392  dir = (directory_type *) malloc(sizeof(* Line 427  dir = (directory_type *) malloc(sizeof(*
427  if ((pattern == NULL) || (dir == NULL))  if ((pattern == NULL) || (dir == NULL))
428    {    {
429    fprintf(stderr, "pcregrep: malloc failed\n");    fprintf(stderr, "pcregrep: malloc failed\n");
430    exit(2);    pcregrep_exit(2);
431    }    }
432  memcpy(pattern, filename, len);  memcpy(pattern, filename, len);
433  memcpy(&(pattern[len]), "\\*", 3);  memcpy(&(pattern[len]), "\\*", 3);
# Line 451  return !isdirectory(filename); Line 486  return !isdirectory(filename);
486  }  }
487    
488    
489  /************* Test stdout for being a terminal in Win32 **********/  /************* Test for a terminal in Win32 **********/
490    
491  /* I don't know how to do this; assume never */  /* I don't know how to do this; assume never */
492    
# Line 461  is_stdout_tty(void) Line 496  is_stdout_tty(void)
496  return FALSE;  return FALSE;
497  }  }
498    
499    static BOOL
500    is_file_tty(FILE *f)
501    {
502    return FALSE;
503    }
504    
505    
506  /************* Directory scanning when we can't do it ***********/  /************* Directory scanning when we can't do it ***********/
507    
# Line 483  void closedirectory(directory_type *dir) Line 524  void closedirectory(directory_type *dir)
524  int isregfile(char *filename) { return 1; }  int isregfile(char *filename) { return 1; }
525    
526    
527  /************* Test stdout for being a terminal when we can't do it **********/  /************* Test for a terminal when we can't do it **********/
528    
529  static BOOL  static BOOL
530  is_stdout_tty(void)  is_stdout_tty(void)
# Line 491  is_stdout_tty(void) Line 532  is_stdout_tty(void)
532  return FALSE;  return FALSE;
533  }  }
534    
535    static BOOL
536    is_file_tty(FILE *f)
537    {
538    return FALSE;
539    }
540    
541  #endif  #endif
542    
# Line 519  return sys_errlist[n]; Line 565  return sys_errlist[n];
565    
566    
567  /*************************************************  /*************************************************
568    *         Exit from the program                  *
569    *************************************************/
570    
571    /* If there has been a resource error, give a suitable message.
572    
573    Argument:  the return code
574    Returns:   does not return
575    */
576    
577    static void
578    pcregrep_exit(int rc)
579    {
580    if (resource_error)
581      {
582      fprintf(stderr, "pcregrep: Error %d or %d means that a resource limit "
583        "was exceeded.\n", PCRE_ERROR_MATCHLIMIT, PCRE_ERROR_RECURSIONLIMIT);
584      fprintf(stderr, "pcregrep: Check your regex for nested unlimited loops.\n");
585      }
586    
587    exit(rc);
588    }
589    
590    
591    
592    /*************************************************
593    *            Read one line of input              *
594    *************************************************/
595    
596    /* Normally, input is read using fread() into a large buffer, so many lines may
597    be read at once. However, doing this for tty input means that no output appears
598    until a lot of input has been typed. Instead, tty input is handled line by
599    line. We cannot use fgets() for this, because it does not stop at a binary
600    zero, and therefore there is no way of telling how many characters it has read,
601    because there may be binary zeros embedded in the data.
602    
603    Arguments:
604      buffer     the buffer to read into
605      length     the maximum number of characters to read
606      f          the file
607    
608    Returns:     the number of characters read, zero at end of file
609    */
610    
611    static int
612    read_one_line(char *buffer, int length, FILE *f)
613    {
614    int c;
615    int yield = 0;
616    while ((c = fgetc(f)) != EOF)
617      {
618      buffer[yield++] = c;
619      if (c == '\n' || yield >= length) break;
620      }
621    return yield;
622    }
623    
624    
625    
626    /*************************************************
627  *             Find end of line                   *  *             Find end of line                   *
628  *************************************************/  *************************************************/
629    
# Line 813  if (after_context > 0 && lastmatchnumber Line 918  if (after_context > 0 && lastmatchnumber
918      if (printname != NULL) fprintf(stdout, "%s-", printname);      if (printname != NULL) fprintf(stdout, "%s-", printname);
919      if (number) fprintf(stdout, "%d-", lastmatchnumber++);      if (number) fprintf(stdout, "%d-", lastmatchnumber++);
920      pp = end_of_line(pp, endptr, &ellength);      pp = end_of_line(pp, endptr, &ellength);
921      fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout);      FWRITE(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
922      lastmatchrestart = pp;      lastmatchrestart = pp;
923      }      }
924    hyphenpending = TRUE;    hyphenpending = TRUE;
# Line 845  static BOOL Line 950  static BOOL
950  match_patterns(char *matchptr, size_t length, int *offsets, int *mrc)  match_patterns(char *matchptr, size_t length, int *offsets, int *mrc)
951  {  {
952  int i;  int i;
953    size_t slen = length;
954    const char *msg = "this text:\n\n";
955    if (slen > 200)
956      {
957      slen = 200;
958      msg = "text that starts:\n\n";
959      }
960  for (i = 0; i < pattern_count; i++)  for (i = 0; i < pattern_count; i++)
961    {    {
962    *mrc = pcre_exec(pattern_list[i], hints_list[i], matchptr, length, 0,    *mrc = pcre_exec(pattern_list[i], hints_list[i], matchptr, (int)length, 0,
963      PCRE_NOTEMPTY, offsets, OFFSET_SIZE);      PCRE_NOTEMPTY, offsets, OFFSET_SIZE);
964    if (*mrc >= 0) return TRUE;    if (*mrc >= 0) return TRUE;
965    if (*mrc == PCRE_ERROR_NOMATCH) continue;    if (*mrc == PCRE_ERROR_NOMATCH) continue;
966    fprintf(stderr, "pcregrep: pcre_exec() error %d while matching ", *mrc);    fprintf(stderr, "pcregrep: pcre_exec() gave error %d while matching ", *mrc);
967    if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);    if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);
968    fprintf(stderr, "this text:\n");    fprintf(stderr, "%s", msg);
969    fwrite(matchptr, 1, length, stderr);  /* In case binary zero included */    FWRITE(matchptr, 1, slen, stderr);   /* In case binary zero included */
970    fprintf(stderr, "\n");    fprintf(stderr, "\n\n");
971    if (error_count == 0 &&    if (*mrc == PCRE_ERROR_MATCHLIMIT || *mrc == PCRE_ERROR_RECURSIONLIMIT)
972        (*mrc == PCRE_ERROR_MATCHLIMIT || *mrc == PCRE_ERROR_RECURSIONLIMIT))      resource_error = TRUE;
     {  
     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");  
     }  
973    if (error_count++ > 20)    if (error_count++ > 20)
974      {      {
975      fprintf(stderr, "pcregrep: too many errors - abandoned\n");      fprintf(stderr, "pcregrep: Too many errors - abandoned.\n");
976      exit(2);      pcregrep_exit(2);
977      }      }
978    return invert;    /* No more matching; don't show the line again */    return invert;    /* No more matching; don't show the line again */
979    }    }
# Line 916  char *ptr = buffer; Line 1023  char *ptr = buffer;
1023  char *endptr;  char *endptr;
1024  size_t bufflength;  size_t bufflength;
1025  BOOL endhyphenpending = FALSE;  BOOL endhyphenpending = FALSE;
1026    BOOL input_line_buffered = line_buffered;
1027  FILE *in = NULL;                    /* Ensure initialized */  FILE *in = NULL;                    /* Ensure initialized */
1028    
1029  #ifdef SUPPORT_LIBZ  #ifdef SUPPORT_LIBZ
# Line 953  else Line 1061  else
1061    
1062    {    {
1063    in = (FILE *)handle;    in = (FILE *)handle;
1064    bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);    if (is_file_tty(in)) input_line_buffered = TRUE;
1065      bufflength = input_line_buffered?
1066        read_one_line(buffer, 3*MBUFTHIRD, in) :
1067        fread(buffer, 1, 3*MBUFTHIRD, in);
1068    }    }
1069    
1070  endptr = buffer + bufflength;  endptr = buffer + bufflength;
# Line 1002  while (ptr < endptr) Line 1113  while (ptr < endptr)
1113            ptr = malloc(newlen + 1);            ptr = malloc(newlen + 1);
1114            if (!ptr) {            if (!ptr) {
1115                    printf("out of memory");                    printf("out of memory");
1116                    exit(2);                    pcregrep_exit(2);
1117            }            }
1118            endptr = ptr;            endptr = ptr;
1119            strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);            strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);
# Line 1072  while (ptr < endptr) Line 1183  while (ptr < endptr)
1183    
1184      else if (quiet) return 0;      else if (quiet) return 0;
1185    
1186      /* The --only-matching option prints just the substring that matched, and      /* The --only-matching option prints just the substring that matched, or a
1187      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
1188      matching substring (they both force --only-matching). None of these options      --file-offsets and --line-offsets options output offsets for the matching
1189        substring (they both force --only-matching = 0). None of these options
1190      prints any context. Afterwards, adjust the start and length, and then jump      prints any context. Afterwards, adjust the start and length, and then jump
1191      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
1192      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
1193      return code is set. */      be useful because the return code is set. */
1194    
1195      else if (only_matching)      else if (only_matching >= 0)
1196        {        {
1197        if (!invert)        if (!invert)
1198          {          {
1199          if (printname != NULL) fprintf(stdout, "%s:", printname);          if (printname != NULL) fprintf(stdout, "%s:", printname);
1200          if (number) fprintf(stdout, "%d:", linenumber);          if (number) fprintf(stdout, "%d:", linenumber);
1201          if (line_offsets)          if (line_offsets)
1202            fprintf(stdout, "%d,%d", (int)(matchptr + offsets[0] - ptr),            fprintf(stdout, "%d,%d\n", (int)(matchptr + offsets[0] - ptr),
1203              offsets[1] - offsets[0]);              offsets[1] - offsets[0]);
1204          else if (file_offsets)          else if (file_offsets)
1205            fprintf(stdout, "%d,%d", (int)(filepos + matchptr + offsets[0] - ptr),            fprintf(stdout, "%d,%d\n",
1206                (int)(filepos + matchptr + offsets[0] - ptr),
1207              offsets[1] - offsets[0]);              offsets[1] - offsets[0]);
1208          else          else if (only_matching < mrc)
1209            {            {
1210            if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);            int plen = offsets[2*only_matching + 1] - offsets[2*only_matching];
1211            fwrite(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);            if (plen > 0)
1212            if (do_colour) fprintf(stdout, "%c[00m", 0x1b);              {
1213                if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1214                FWRITE(matchptr + offsets[only_matching*2], 1, plen, stdout);
1215                if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
1216                fprintf(stdout, "\n");
1217                }
1218            }            }
1219          fprintf(stdout, "\n");          else if (printname != NULL || number) fprintf(stdout, "\n");
1220          matchptr += offsets[1];          matchptr += offsets[1];
1221          length -= offsets[1];          length -= offsets[1];
1222          match = FALSE;          match = FALSE;
1223            if (line_buffered) fflush(stdout);
1224            rc = 0;    /* Had some success */
1225          goto ONLY_MATCHING_RESTART;          goto ONLY_MATCHING_RESTART;
1226          }          }
1227        }        }
# Line 1137  while (ptr < endptr) Line 1257  while (ptr < endptr)
1257            if (printname != NULL) fprintf(stdout, "%s-", printname);            if (printname != NULL) fprintf(stdout, "%s-", printname);
1258            if (number) fprintf(stdout, "%d-", lastmatchnumber++);            if (number) fprintf(stdout, "%d-", lastmatchnumber++);
1259            pp = end_of_line(pp, endptr, &ellength);            pp = end_of_line(pp, endptr, &ellength);
1260            fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout);            FWRITE(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
1261            lastmatchrestart = pp;            lastmatchrestart = pp;
1262            }            }
1263          if (lastmatchrestart != ptr) hyphenpending = TRUE;          if (lastmatchrestart != ptr) hyphenpending = TRUE;
# Line 1177  while (ptr < endptr) Line 1297  while (ptr < endptr)
1297            if (printname != NULL) fprintf(stdout, "%s-", printname);            if (printname != NULL) fprintf(stdout, "%s-", printname);
1298            if (number) fprintf(stdout, "%d-", linenumber - linecount--);            if (number) fprintf(stdout, "%d-", linenumber - linecount--);
1299            pp = end_of_line(pp, endptr, &ellength);            pp = end_of_line(pp, endptr, &ellength);
1300            fwrite(p, 1, pp - p, stdout);            FWRITE(p, 1, pp - p, stdout);
1301            p = pp;            p = pp;
1302            }            }
1303          }          }
# Line 1227  while (ptr < endptr) Line 1347  while (ptr < endptr)
1347          {          {
1348          int first = S_arg * 2;          int first = S_arg * 2;
1349          int last  = first + 1;          int last  = first + 1;
1350          fwrite(ptr, 1, offsets[first], stdout);          FWRITE(ptr, 1, offsets[first], stdout);
1351          fprintf(stdout, "X");          fprintf(stdout, "X");
1352          fwrite(ptr + offsets[last], 1, linelength - offsets[last], stdout);          FWRITE(ptr + offsets[last], 1, linelength - offsets[last], stdout);
1353          }          }
1354        else        else
1355  #endif  #endif
# Line 1240  while (ptr < endptr) Line 1360  while (ptr < endptr)
1360        if (do_colour)        if (do_colour)
1361          {          {
1362          int last_offset = 0;          int last_offset = 0;
1363          fwrite(ptr, 1, offsets[0], stdout);          FWRITE(ptr, 1, offsets[0], stdout);
1364          fprintf(stdout, "%c[%sm", 0x1b, colour_string);          fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1365          fwrite(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);          FWRITE(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1366          fprintf(stdout, "%c[00m", 0x1b);          fprintf(stdout, "%c[00m", 0x1b);
1367          for (;;)          for (;;)
1368            {            {
# Line 1250  while (ptr < endptr) Line 1370  while (ptr < endptr)
1370            matchptr += offsets[1];            matchptr += offsets[1];
1371            length -= offsets[1];            length -= offsets[1];
1372            if (!match_patterns(matchptr, length, offsets, &mrc)) break;            if (!match_patterns(matchptr, length, offsets, &mrc)) break;
1373            fwrite(matchptr, 1, offsets[0], stdout);            FWRITE(matchptr, 1, offsets[0], stdout);
1374            fprintf(stdout, "%c[%sm", 0x1b, colour_string);            fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1375            fwrite(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);            FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1376            fprintf(stdout, "%c[00m", 0x1b);            fprintf(stdout, "%c[00m", 0x1b);
1377            }            }
1378          fwrite(ptr + last_offset, 1, (linelength + endlinelength) - last_offset,          FWRITE(ptr + last_offset, 1,
1379            stdout);            (linelength + endlinelength) - last_offset, stdout);
1380          }          }
1381    
1382        /* Not colouring; no need to search for further matches */        /* Not colouring; no need to search for further matches */
1383    
1384        else fwrite(ptr, 1, linelength + endlinelength, stdout);        else FWRITE(ptr, 1, linelength + endlinelength, stdout);
1385        }        }
1386    
1387      /* 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
1388        given, flush the output. */
1389    
1390        if (line_buffered) fflush(stdout);
1391      rc = 0;    /* Had some success */      rc = 0;    /* Had some success */
1392    
1393      /* Remember where the last match happened for after_context. We remember      /* Remember where the last match happened for after_context. We remember
# Line 1297  while (ptr < endptr) Line 1419  while (ptr < endptr)
1419    offset to the current line is maintained in filepos. */    offset to the current line is maintained in filepos. */
1420    
1421    ptr += linelength + endlinelength;    ptr += linelength + endlinelength;
1422    filepos += linelength + endlinelength;    filepos += (int)(linelength + endlinelength);
1423    linenumber++;    linenumber++;
1424    
1425      /* If input is line buffered, and the buffer is not yet full, read another
1426      line and add it into the buffer. */
1427    
1428      if (input_line_buffered && bufflength < sizeof(buffer))
1429        {
1430        int add = read_one_line(ptr, sizeof(buffer) - (ptr - buffer), in);
1431        bufflength += add;
1432        endptr += add;
1433        }
1434    
1435    /* 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
1436    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
1437    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 1334  while (ptr < endptr) Line 1466  while (ptr < endptr)
1466      else      else
1467  #endif  #endif
1468    
1469      bufflength = 2*MBUFTHIRD + fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in);      bufflength = 2*MBUFTHIRD +
1470          (input_line_buffered?
1471           read_one_line(buffer + 2*MBUFTHIRD, MBUFTHIRD, in) :
1472           fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in));
1473      endptr = buffer + bufflength;      endptr = buffer + bufflength;
1474    
1475      /* Adjust any last match point */      /* Adjust any last match point */
# Line 1347  while (ptr < endptr) Line 1481  while (ptr < endptr)
1481  /* 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
1482  hyphenpending if it prints something. */  hyphenpending if it prints something. */
1483    
1484  if (!only_matching && !count_only)  if (only_matching < 0 && !count_only)
1485    {    {
1486    do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);    do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
1487    hyphenpending |= endhyphenpending;    hyphenpending |= endhyphenpending;
# Line 1451  if ((sep = isdirectory(pathname)) != 0) Line 1585  if ((sep = isdirectory(pathname)) != 0)
1585        {        {
1586        int frc, nflen;        int frc, nflen;
1587        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);
1588        nflen = strlen(nextfile);        nflen = (int)(strlen(nextfile));
1589    
1590        if (isdirectory(buffer))        if (isdirectory(buffer))
1591          {          {
# Line 1495  skipping was not requested. The scan pro Line 1629  skipping was not requested. The scan pro
1629  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
1630  the file name, or the filename was forced (-H). */  the file name, or the filename was forced (-H). */
1631    
1632  pathlen = strlen(pathname);  pathlen = (int)(strlen(pathname));
1633    
1634  /* 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. */
1635    
# Line 1657  for (op = optionlist; op->one_char != 0; Line 1791  for (op = optionlist; op->one_char != 0;
1791    {    {
1792    int n;    int n;
1793    char s[4];    char s[4];
1794    
1795      /* Two options were accidentally implemented and documented with underscores
1796      instead of hyphens in their names, something that was not noticed for quite a
1797      few releases. When fixing this, I left the underscored versions in the list
1798      in case people were using them. However, we don't want to display them in the
1799      help data. There are no other options that contain underscores, and we do not
1800      expect ever to implement such options. Therefore, just omit any option that
1801      contains an underscore. */
1802    
1803      if (strchr(op->long_name, '_') != NULL) continue;
1804    
1805    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, "   ");
1806    n = 30 - printf("  %s --%s", s, op->long_name);    n = 31 - printf("  %s --%s", s, op->long_name);
1807    if (n < 1) n = 1;    if (n < 1) n = 1;
1808    printf("%.*s%s\n", n, "                    ", op->help_text);    printf("%.*s%s\n", n, "                     ", op->help_text);
1809    }    }
1810    
1811  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 1684  handle_option(int letter, int options) Line 1829  handle_option(int letter, int options)
1829  switch(letter)  switch(letter)
1830    {    {
1831    case N_FOFFSETS: file_offsets = TRUE; break;    case N_FOFFSETS: file_offsets = TRUE; break;
1832    case N_HELP: help(); exit(0);    case N_HELP: help(); pcregrep_exit(0);
1833    case N_LOFFSETS: line_offsets = number = TRUE; break;    case N_LOFFSETS: line_offsets = number = TRUE; break;
1834      case N_LBUFFER: line_buffered = TRUE; break;
1835    case 'c': count_only = TRUE; break;    case 'c': count_only = TRUE; break;
1836    case 'F': process_options |= PO_FIXED_STRINGS; break;    case 'F': process_options |= PO_FIXED_STRINGS; break;
1837    case 'H': filenames = FN_FORCE; break;    case 'H': filenames = FN_FORCE; break;
# Line 1695  switch(letter) Line 1841  switch(letter)
1841    case 'L': filenames = FN_NOMATCH_ONLY; break;    case 'L': filenames = FN_NOMATCH_ONLY; break;
1842    case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;    case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;
1843    case 'n': number = TRUE; break;    case 'n': number = TRUE; break;
1844    case 'o': only_matching = TRUE; break;    case 'o': only_matching = 0; break;
1845    case 'q': quiet = TRUE; break;    case 'q': quiet = TRUE; break;
1846    case 'r': dee_action = dee_RECURSE; break;    case 'r': dee_action = dee_RECURSE; break;
1847    case 's': silent = TRUE; break;    case 's': silent = TRUE; break;
# Line 1706  switch(letter) Line 1852  switch(letter)
1852    
1853    case 'V':    case 'V':
1854    fprintf(stderr, "pcregrep version %s\n", pcre_version());    fprintf(stderr, "pcregrep version %s\n", pcre_version());
1855    exit(0);    pcregrep_exit(0);
1856    break;    break;
1857    
1858    default:    default:
1859    fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);    fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);
1860    exit(usage(2));    pcregrep_exit(usage(2));
1861    }    }
1862    
1863  return options;  return options;
# Line 1907  for (i = 1; i < argc; i++) Line 2053  for (i = 1; i < argc; i++)
2053    if (argv[i][1] == 0)    if (argv[i][1] == 0)
2054      {      {
2055      if (pattern_filename != NULL || pattern_count > 0) break;      if (pattern_filename != NULL || pattern_count > 0) break;
2056        else exit(usage(2));        else pcregrep_exit(usage(2));
2057      }      }
2058    
2059    /* Handle a long name option, or -- to terminate the options */    /* Handle a long name option, or -- to terminate the options */
# Line 1947  for (i = 1; i < argc; i++) Line 2093  for (i = 1; i < argc; i++)
2093            }            }
2094          else                 /* Special case xxx=data */          else                 /* Special case xxx=data */
2095            {            {
2096            int oplen = equals - op->long_name;            int oplen = (int)(equals - op->long_name);
2097            int arglen = (argequals == NULL)? (int)strlen(arg) : argequals - arg;            int arglen = (argequals == NULL)?
2098                (int)strlen(arg) : (int)(argequals - arg);
2099            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)
2100              {              {
2101              option_data = arg + arglen;              option_data = arg + arglen;
# Line 1969  for (i = 1; i < argc; i++) Line 2116  for (i = 1; i < argc; i++)
2116          char buff1[24];          char buff1[24];
2117          char buff2[24];          char buff2[24];
2118    
2119          int baselen = opbra - op->long_name;          int baselen = (int)(opbra - op->long_name);
2120          int fulllen = strchr(op->long_name, ')') - op->long_name + 1;          int fulllen = (int)(strchr(op->long_name, ')') - op->long_name + 1);
2121          int arglen = (argequals == NULL || equals == NULL)?          int arglen = (argequals == NULL || equals == NULL)?
2122            (int)strlen(arg) : argequals - arg;            (int)strlen(arg) : (int)(argequals - arg);
2123    
2124          sprintf(buff1, "%.*s", baselen, op->long_name);          sprintf(buff1, "%.*s", baselen, op->long_name);
2125          sprintf(buff2, "%s%.*s", buff1, fulllen - baselen - 2, opbra + 1);          sprintf(buff2, "%s%.*s", buff1, fulllen - baselen - 2, opbra + 1);
# Line 1997  for (i = 1; i < argc; i++) Line 2144  for (i = 1; i < argc; i++)
2144      if (op->one_char == 0)      if (op->one_char == 0)
2145        {        {
2146        fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);        fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);
2147        exit(usage(2));        pcregrep_exit(usage(2));
2148        }        }
2149      }      }
2150    
# Line 2034  for (i = 1; i < argc; i++) Line 2181  for (i = 1; i < argc; i++)
2181      while (*s != 0)      while (*s != 0)
2182        {        {
2183        for (op = optionlist; op->one_char != 0; op++)        for (op = optionlist; op->one_char != 0; op++)
2184          { if (*s == op->one_char) break; }          {
2185            if (*s == op->one_char) break;
2186            }
2187        if (op->one_char == 0)        if (op->one_char == 0)
2188          {          {
2189          fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",          fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",
2190            *s, argv[i]);            *s, argv[i]);
2191          exit(usage(2));          pcregrep_exit(usage(2));
2192          }          }
2193        if (op->type != OP_NODATA || s[1] == 0)  
2194          {        /* Check for a single-character option that has data: OP_OP_NUMBER
2195          option_data = s+1;        is used for one that either has a numerical number or defaults, i.e. the
2196          break;        data is optional. If a digit follows, there is data; if not, carry on
2197          with other single-character options in the same string. */
2198    
2199          option_data = s+1;
2200          if (op->type == OP_OP_NUMBER)
2201            {
2202            if (isdigit((unsigned char)s[1])) break;
2203          }          }
2204          else   /* Check for end or a dataless option */
2205            {
2206            if (op->type != OP_NODATA || s[1] == 0) break;
2207            }
2208    
2209          /* Handle a single-character option with no data, then loop for the
2210          next character in the string. */
2211    
2212        pcre_options = handle_option(*s++, pcre_options);        pcre_options = handle_option(*s++, pcre_options);
2213        }        }
2214      }      }
# Line 2062  for (i = 1; i < argc; i++) Line 2225  for (i = 1; i < argc; i++)
2225    
2226    /* 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
2227    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
2228    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",
2229    Jeffrey Friedl's special -S debugging option. */    "only-matching", and Jeffrey Friedl's special -S debugging option. */
2230    
2231    if (*option_data == 0 &&    if (*option_data == 0 &&
2232        (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))        (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))
# Line 2073  for (i = 1; i < argc; i++) Line 2236  for (i = 1; i < argc; i++)
2236        case N_COLOUR:        case N_COLOUR:
2237        colour_option = (char *)"auto";        colour_option = (char *)"auto";
2238        break;        break;
2239    
2240          case 'o':
2241          only_matching = 0;
2242          break;
2243    
2244  #ifdef JFRIEDL_DEBUG  #ifdef JFRIEDL_DEBUG
2245        case 'S':        case 'S':
2246        S_arg = 0;        S_arg = 0;
# Line 2089  for (i = 1; i < argc; i++) Line 2257  for (i = 1; i < argc; i++)
2257      if (i >= argc - 1 || longopwasequals)      if (i >= argc - 1 || longopwasequals)
2258        {        {
2259        fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);        fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);
2260        exit(usage(2));        pcregrep_exit(usage(2));
2261        }        }
2262      option_data = argv[++i];      option_data = argv[++i];
2263      }      }
# Line 2114  for (i = 1; i < argc; i++) Line 2282  for (i = 1; i < argc; i++)
2282      {      {
2283      *((char **)op->dataptr) = option_data;      *((char **)op->dataptr) = option_data;
2284      }      }
2285    
2286      /* Avoid the use of strtoul() because SunOS4 doesn't have it. This is used
2287      only for unpicking arguments, so just keep it simple. */
2288    
2289    else    else
2290      {      {
2291      char *endptr;      unsigned long int n = 0;
2292      int n = strtoul(option_data, &endptr, 10);      char *endptr = option_data;
2293        while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++;
2294        while (isdigit((unsigned char)(*endptr)))
2295          n = n * 10 + (int)(*endptr++ - '0');
2296      if (*endptr != 0)      if (*endptr != 0)
2297        {        {
2298        if (longop)        if (longop)
2299          {          {
2300          char *equals = strchr(op->long_name, '=');          char *equals = strchr(op->long_name, '=');
2301          int nlen = (equals == NULL)? (int)strlen(op->long_name) :          int nlen = (equals == NULL)? (int)strlen(op->long_name) :
2302            equals - op->long_name;            (int)(equals - op->long_name);
2303          fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",          fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",
2304            option_data, nlen, op->long_name);            option_data, nlen, op->long_name);
2305          }          }
2306        else        else
2307          fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",          fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",
2308            option_data, op->one_char);            option_data, op->one_char);
2309        exit(usage(2));        pcregrep_exit(usage(2));
2310        }        }
2311      *((int *)op->dataptr) = n;      *((int *)op->dataptr) = n;
2312      }      }
# Line 2147  if (both_context > 0) Line 2322  if (both_context > 0)
2322    }    }
2323    
2324  /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.  /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.
2325  However, the latter two set the only_matching flag. */  However, the latter two set only_matching. */
2326    
2327  if ((only_matching && (file_offsets || line_offsets)) ||  if ((only_matching >= 0 && (file_offsets || line_offsets)) ||
2328      (file_offsets && line_offsets))      (file_offsets && line_offsets))
2329    {    {
2330    fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "    fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "
2331      "and/or --line-offsets\n");      "and/or --line-offsets\n");
2332    exit(usage(2));    pcregrep_exit(usage(2));
2333    }    }
2334    
2335  if (file_offsets || line_offsets) only_matching = TRUE;  if (file_offsets || line_offsets) only_matching = 0;
2336    
2337  /* 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
2338  LC_ALL environment variable is set, and if so, use it. */  LC_ALL environment variable is set, and if so, use it. */
# Line 2365  for (j = 0; j < pattern_count; j++) Line 2540  for (j = 0; j < pattern_count; j++)
2540      }      }
2541    hint_count++;    hint_count++;
2542    }    }
2543    
2544    /* If --match-limit or --recursion-limit was set, put the value(s) into the
2545    pcre_extra block for each pattern. */
2546    
2547    if (match_limit > 0 || match_limit_recursion > 0)
2548      {
2549      for (j = 0; j < pattern_count; j++)
2550        {
2551        if (hints_list[j] == NULL)
2552          {
2553          hints_list[j] = malloc(sizeof(pcre_extra));
2554          if (hints_list[j] == NULL)
2555            {
2556            fprintf(stderr, "pcregrep: malloc failed\n");
2557            pcregrep_exit(2);
2558            }
2559          }
2560        if (match_limit > 0)
2561          {
2562          hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT;
2563          hints_list[j]->match_limit = match_limit;
2564          }
2565        if (match_limit_recursion > 0)
2566          {
2567          hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
2568          hints_list[j]->match_limit_recursion = match_limit_recursion;
2569          }
2570        }
2571      }
2572    
2573  /* If there are include or exclude patterns, compile them. */  /* If there are include or exclude patterns, compile them. */
2574    
# Line 2447  if (pattern_list != NULL) Line 2651  if (pattern_list != NULL)
2651    }    }
2652  if (hints_list != NULL)  if (hints_list != NULL)
2653    {    {
2654    for (i = 0; i < hint_count; i++) free(hints_list[i]);    for (i = 0; i < hint_count; i++)
2655        {
2656        if (hints_list[i] != NULL) free(hints_list[i]);
2657        }
2658    free(hints_list);    free(hints_list);
2659    }    }
2660  return rc;  pcregrep_exit(rc);
2661    
2662  EXIT2:  EXIT2:
2663  rc = 2;  rc = 2;

Legend:
Removed from v.461  
changed lines
  Added in v.571

webmaster@exim.org
ViewVC Help
Powered by ViewVC 1.1.12