/[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 515 by ph10, Tue May 4 09:12:25 2010 UTC revision 565 by ph10, Sun Oct 31 18:18:48 2010 UTC
# 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  /* 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.  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  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  this, we use a macro that compiles a fudge. Oddly, this does not also seem to
111  apply to fprintf(). */  apply to fprintf(). */
112    
113  #define FWRITE(a,b,c,d) if (fwrite(a,b,c,d)) {}  #define FWRITE(a,b,c,d) if (fwrite(a,b,c,d)) {}
# Line 163  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 206  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 213  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 228  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" },
# Line 339  return (statbuf.st_mode & S_IFMT) == S_I Line 350  return (statbuf.st_mode & S_IFMT) == S_I
350  }  }
351    
352    
353  /************* Test stdout for being a terminal in Unix **********/  /************* Test for a terminal in Unix **********/
354    
355  static BOOL  static BOOL
356  is_stdout_tty(void)  is_stdout_tty(void)
# Line 347  is_stdout_tty(void) Line 358  is_stdout_tty(void)
358  return isatty(fileno(stdout));  return isatty(fileno(stdout));
359  }  }
360    
361    static BOOL
362    is_file_tty(FILE *f)
363    {
364    return isatty(fileno(f));
365    }
366    
367    
368  /************* Directory scanning in Win32 ***********/  /************* Directory scanning in Win32 ***********/
369    
# Line 354  return isatty(fileno(stdout)); Line 371  return isatty(fileno(stdout));
371  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES  Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES
372  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
373  <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.  <windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.
374  */  The double test below stops gcc 4.4.4 grumbling that HAVE_WINDOWS_H is
375    undefined when it is indeed undefined. */
376    
377  #elif HAVE_WINDOWS_H  #elif defined HAVE_WINDOWS_H && HAVE_WINDOWS_H
378    
379  #ifndef STRICT  #ifndef STRICT
380  # define STRICT  # define STRICT
# Line 400  dir = (directory_type *) malloc(sizeof(* Line 418  dir = (directory_type *) malloc(sizeof(*
418  if ((pattern == NULL) || (dir == NULL))  if ((pattern == NULL) || (dir == NULL))
419    {    {
420    fprintf(stderr, "pcregrep: malloc failed\n");    fprintf(stderr, "pcregrep: malloc failed\n");
421    exit(2);    pcregrep_exit(2);
422    }    }
423  memcpy(pattern, filename, len);  memcpy(pattern, filename, len);
424  memcpy(&(pattern[len]), "\\*", 3);  memcpy(&(pattern[len]), "\\*", 3);
# Line 459  return !isdirectory(filename); Line 477  return !isdirectory(filename);
477  }  }
478    
479    
480  /************* Test stdout for being a terminal in Win32 **********/  /************* Test for a terminal in Win32 **********/
481    
482  /* I don't know how to do this; assume never */  /* I don't know how to do this; assume never */
483    
# Line 469  is_stdout_tty(void) Line 487  is_stdout_tty(void)
487  return FALSE;  return FALSE;
488  }  }
489    
490    static BOOL
491    is_file_tty(FILE *f)
492    {
493    return FALSE;
494    }
495    
496    
497  /************* Directory scanning when we can't do it ***********/  /************* Directory scanning when we can't do it ***********/
498    
# Line 491  void closedirectory(directory_type *dir) Line 515  void closedirectory(directory_type *dir)
515  int isregfile(char *filename) { return 1; }  int isregfile(char *filename) { return 1; }
516    
517    
518  /************* Test stdout for being a terminal when we can't do it **********/  /************* Test for a terminal when we can't do it **********/
519    
520  static BOOL  static BOOL
521  is_stdout_tty(void)  is_stdout_tty(void)
# Line 499  is_stdout_tty(void) Line 523  is_stdout_tty(void)
523  return FALSE;  return FALSE;
524  }  }
525    
526    static BOOL
527    is_file_tty(FILE *f)
528    {
529    return FALSE;
530    }
531    
532  #endif  #endif
533    
# Line 527  return sys_errlist[n]; Line 556  return sys_errlist[n];
556    
557    
558  /*************************************************  /*************************************************
559    *         Exit from the program                  *
560    *************************************************/
561    
562    /* If there has been a resource error, give a suitable message.
563    
564    Argument:  the return code
565    Returns:   does not return
566    */
567    
568    static void
569    pcregrep_exit(int rc)
570    {
571    if (resource_error)
572      {
573      fprintf(stderr, "pcregrep: Error %d or %d means that a resource limit "
574        "was exceeded.\n", PCRE_ERROR_MATCHLIMIT, PCRE_ERROR_RECURSIONLIMIT);
575      fprintf(stderr, "pcregrep: Check your regex for nested unlimited loops.\n");
576      }
577    
578    exit(rc);
579    }
580    
581    
582    
583    /*************************************************
584    *            Read one line of input              *
585    *************************************************/
586    
587    /* Normally, input is read using fread() into a large buffer, so many lines may
588    be read at once. However, doing this for tty input means that no output appears
589    until a lot of input has been typed. Instead, tty input is handled line by
590    line. We cannot use fgets() for this, because it does not stop at a binary
591    zero, and therefore there is no way of telling how many characters it has read,
592    because there may be binary zeros embedded in the data.
593    
594    Arguments:
595      buffer     the buffer to read into
596      length     the maximum number of characters to read
597      f          the file
598    
599    Returns:     the number of characters read, zero at end of file
600    */
601    
602    static int
603    read_one_line(char *buffer, int length, FILE *f)
604    {
605    int c;
606    int yield = 0;
607    while ((c = fgetc(f)) != EOF)
608      {
609      buffer[yield++] = c;
610      if (c == '\n' || yield >= length) break;
611      }
612    return yield;
613    }
614    
615    
616    
617    /*************************************************
618  *             Find end of line                   *  *             Find end of line                   *
619  *************************************************/  *************************************************/
620    
# Line 853  static BOOL Line 941  static BOOL
941  match_patterns(char *matchptr, size_t length, int *offsets, int *mrc)  match_patterns(char *matchptr, size_t length, int *offsets, int *mrc)
942  {  {
943  int i;  int i;
944    size_t slen = length;
945    const char *msg = "this text:\n\n";
946    if (slen > 200)
947      {
948      slen = 200;
949      msg = "text that starts:\n\n";
950      }
951  for (i = 0; i < pattern_count; i++)  for (i = 0; i < pattern_count; i++)
952    {    {
953    *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,
954      PCRE_NOTEMPTY, offsets, OFFSET_SIZE);      PCRE_NOTEMPTY, offsets, OFFSET_SIZE);
955    if (*mrc >= 0) return TRUE;    if (*mrc >= 0) return TRUE;
956    if (*mrc == PCRE_ERROR_NOMATCH) continue;    if (*mrc == PCRE_ERROR_NOMATCH) continue;
957    fprintf(stderr, "pcregrep: pcre_exec() error %d while matching ", *mrc);    fprintf(stderr, "pcregrep: pcre_exec() gave error %d while matching ", *mrc);
958    if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);    if (pattern_count > 1) fprintf(stderr, "pattern number %d to ", i+1);
959    fprintf(stderr, "this text:\n");    fprintf(stderr, "%s", msg);
960    FWRITE(matchptr, 1, length, stderr);   /* In case binary zero included */    FWRITE(matchptr, 1, slen, stderr);   /* In case binary zero included */
961    fprintf(stderr, "\n");    fprintf(stderr, "\n\n");
962    if (error_count == 0 &&    if (*mrc == PCRE_ERROR_MATCHLIMIT || *mrc == PCRE_ERROR_RECURSIONLIMIT)
963        (*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");  
     }  
964    if (error_count++ > 20)    if (error_count++ > 20)
965      {      {
966      fprintf(stderr, "pcregrep: too many errors - abandoned\n");      fprintf(stderr, "pcregrep: Too many errors - abandoned.\n");
967      exit(2);      pcregrep_exit(2);
968      }      }
969    return invert;    /* No more matching; don't show the line again */    return invert;    /* No more matching; don't show the line again */
970    }    }
# Line 924  char *ptr = buffer; Line 1014  char *ptr = buffer;
1014  char *endptr;  char *endptr;
1015  size_t bufflength;  size_t bufflength;
1016  BOOL endhyphenpending = FALSE;  BOOL endhyphenpending = FALSE;
1017    BOOL input_line_buffered = line_buffered;
1018  FILE *in = NULL;                    /* Ensure initialized */  FILE *in = NULL;                    /* Ensure initialized */
1019    
1020  #ifdef SUPPORT_LIBZ  #ifdef SUPPORT_LIBZ
# Line 961  else Line 1052  else
1052    
1053    {    {
1054    in = (FILE *)handle;    in = (FILE *)handle;
1055    bufflength = fread(buffer, 1, 3*MBUFTHIRD, in);    if (is_file_tty(in)) input_line_buffered = TRUE;
1056      bufflength = input_line_buffered?
1057        read_one_line(buffer, 3*MBUFTHIRD, in) :
1058        fread(buffer, 1, 3*MBUFTHIRD, in);
1059    }    }
1060    
1061  endptr = buffer + bufflength;  endptr = buffer + bufflength;
# Line 1010  while (ptr < endptr) Line 1104  while (ptr < endptr)
1104            ptr = malloc(newlen + 1);            ptr = malloc(newlen + 1);
1105            if (!ptr) {            if (!ptr) {
1106                    printf("out of memory");                    printf("out of memory");
1107                    exit(2);                    pcregrep_exit(2);
1108            }            }
1109            endptr = ptr;            endptr = ptr;
1110            strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);            strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);
# Line 1080  while (ptr < endptr) Line 1174  while (ptr < endptr)
1174    
1175      else if (quiet) return 0;      else if (quiet) return 0;
1176    
1177      /* The --only-matching option prints just the substring that matched, and      /* The --only-matching option prints just the substring that matched, or a
1178      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
1179      matching substring (they both force --only-matching). None of these options      --file-offsets and --line-offsets options output offsets for the matching
1180        substring (they both force --only-matching = 0). None of these options
1181      prints any context. Afterwards, adjust the start and length, and then jump      prints any context. Afterwards, adjust the start and length, and then jump
1182      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
1183      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
1184      return code is set. */      be useful because the return code is set. */
1185    
1186      else if (only_matching)      else if (only_matching >= 0)
1187        {        {
1188        if (!invert)        if (!invert)
1189          {          {
1190          if (printname != NULL) fprintf(stdout, "%s:", printname);          if (printname != NULL) fprintf(stdout, "%s:", printname);
1191          if (number) fprintf(stdout, "%d:", linenumber);          if (number) fprintf(stdout, "%d:", linenumber);
1192          if (line_offsets)          if (line_offsets)
1193            fprintf(stdout, "%d,%d", (int)(matchptr + offsets[0] - ptr),            fprintf(stdout, "%d,%d\n", (int)(matchptr + offsets[0] - ptr),
1194              offsets[1] - offsets[0]);              offsets[1] - offsets[0]);
1195          else if (file_offsets)          else if (file_offsets)
1196            fprintf(stdout, "%d,%d", (int)(filepos + matchptr + offsets[0] - ptr),            fprintf(stdout, "%d,%d\n",
1197                (int)(filepos + matchptr + offsets[0] - ptr),
1198              offsets[1] - offsets[0]);              offsets[1] - offsets[0]);
1199          else          else if (only_matching < mrc)
1200            {            {
1201            if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);            int plen = offsets[2*only_matching + 1] - offsets[2*only_matching];
1202            FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);            if (plen > 0)
1203            if (do_colour) fprintf(stdout, "%c[00m", 0x1b);              {
1204                if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
1205                FWRITE(matchptr + offsets[only_matching*2], 1, plen, stdout);
1206                if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
1207                fprintf(stdout, "\n");
1208                }
1209            }            }
1210          fprintf(stdout, "\n");          else if (printname != NULL || number) fprintf(stdout, "\n");
1211          matchptr += offsets[1];          matchptr += offsets[1];
1212          length -= offsets[1];          length -= offsets[1];
1213          match = FALSE;          match = FALSE;
1214            if (line_buffered) fflush(stdout);
1215            rc = 0;    /* Had some success */
1216          goto ONLY_MATCHING_RESTART;          goto ONLY_MATCHING_RESTART;
1217          }          }
1218        }        }
# Line 1263  while (ptr < endptr) Line 1366  while (ptr < endptr)
1366            FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);            FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
1367            fprintf(stdout, "%c[00m", 0x1b);            fprintf(stdout, "%c[00m", 0x1b);
1368            }            }
1369          FWRITE(ptr + last_offset, 1,          FWRITE(ptr + last_offset, 1,
1370            (linelength + endlinelength) - last_offset, stdout);            (linelength + endlinelength) - last_offset, stdout);
1371          }          }
1372    
# Line 1272  while (ptr < endptr) Line 1375  while (ptr < endptr)
1375        else FWRITE(ptr, 1, linelength + endlinelength, stdout);        else FWRITE(ptr, 1, linelength + endlinelength, stdout);
1376        }        }
1377    
1378      /* 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
1379        given, flush the output. */
1380    
1381        if (line_buffered) fflush(stdout);
1382      rc = 0;    /* Had some success */      rc = 0;    /* Had some success */
1383    
1384      /* Remember where the last match happened for after_context. We remember      /* Remember where the last match happened for after_context. We remember
# Line 1305  while (ptr < endptr) Line 1410  while (ptr < endptr)
1410    offset to the current line is maintained in filepos. */    offset to the current line is maintained in filepos. */
1411    
1412    ptr += linelength + endlinelength;    ptr += linelength + endlinelength;
1413    filepos += linelength + endlinelength;    filepos += (int)(linelength + endlinelength);
1414    linenumber++;    linenumber++;
1415    
1416      /* If input is line buffered, and the buffer is not yet full, read another
1417      line and add it into the buffer. */
1418    
1419      if (input_line_buffered && bufflength < sizeof(buffer))
1420        {
1421        int add = read_one_line(ptr, sizeof(buffer) - (ptr - buffer), in);
1422        bufflength += add;
1423        endptr += add;
1424        }
1425    
1426    /* 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
1427    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
1428    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 1342  while (ptr < endptr) Line 1457  while (ptr < endptr)
1457      else      else
1458  #endif  #endif
1459    
1460      bufflength = 2*MBUFTHIRD + fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in);      bufflength = 2*MBUFTHIRD +
1461          (input_line_buffered?
1462           read_one_line(buffer + 2*MBUFTHIRD, MBUFTHIRD, in) :
1463           fread(buffer + 2*MBUFTHIRD, 1, MBUFTHIRD, in));
1464      endptr = buffer + bufflength;      endptr = buffer + bufflength;
1465    
1466      /* Adjust any last match point */      /* Adjust any last match point */
# Line 1355  while (ptr < endptr) Line 1472  while (ptr < endptr)
1472  /* 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
1473  hyphenpending if it prints something. */  hyphenpending if it prints something. */
1474    
1475  if (!only_matching && !count_only)  if (only_matching < 0 && !count_only)
1476    {    {
1477    do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);    do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
1478    hyphenpending |= endhyphenpending;    hyphenpending |= endhyphenpending;
# Line 1459  if ((sep = isdirectory(pathname)) != 0) Line 1576  if ((sep = isdirectory(pathname)) != 0)
1576        {        {
1577        int frc, nflen;        int frc, nflen;
1578        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);        sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile);
1579        nflen = strlen(nextfile);        nflen = (int)(strlen(nextfile));
1580    
1581        if (isdirectory(buffer))        if (isdirectory(buffer))
1582          {          {
# Line 1503  skipping was not requested. The scan pro Line 1620  skipping was not requested. The scan pro
1620  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
1621  the file name, or the filename was forced (-H). */  the file name, or the filename was forced (-H). */
1622    
1623  pathlen = strlen(pathname);  pathlen = (int)(strlen(pathname));
1624    
1625  /* 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. */
1626    
# Line 1692  handle_option(int letter, int options) Line 1809  handle_option(int letter, int options)
1809  switch(letter)  switch(letter)
1810    {    {
1811    case N_FOFFSETS: file_offsets = TRUE; break;    case N_FOFFSETS: file_offsets = TRUE; break;
1812    case N_HELP: help(); exit(0);    case N_HELP: help(); pcregrep_exit(0);
1813    case N_LOFFSETS: line_offsets = number = TRUE; break;    case N_LOFFSETS: line_offsets = number = TRUE; break;
1814      case N_LBUFFER: line_buffered = TRUE; break;
1815    case 'c': count_only = TRUE; break;    case 'c': count_only = TRUE; break;
1816    case 'F': process_options |= PO_FIXED_STRINGS; break;    case 'F': process_options |= PO_FIXED_STRINGS; break;
1817    case 'H': filenames = FN_FORCE; break;    case 'H': filenames = FN_FORCE; break;
# Line 1703  switch(letter) Line 1821  switch(letter)
1821    case 'L': filenames = FN_NOMATCH_ONLY; break;    case 'L': filenames = FN_NOMATCH_ONLY; break;
1822    case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;    case 'M': multiline = TRUE; options |= PCRE_MULTILINE|PCRE_FIRSTLINE; break;
1823    case 'n': number = TRUE; break;    case 'n': number = TRUE; break;
1824    case 'o': only_matching = TRUE; break;    case 'o': only_matching = 0; break;
1825    case 'q': quiet = TRUE; break;    case 'q': quiet = TRUE; break;
1826    case 'r': dee_action = dee_RECURSE; break;    case 'r': dee_action = dee_RECURSE; break;
1827    case 's': silent = TRUE; break;    case 's': silent = TRUE; break;
# Line 1714  switch(letter) Line 1832  switch(letter)
1832    
1833    case 'V':    case 'V':
1834    fprintf(stderr, "pcregrep version %s\n", pcre_version());    fprintf(stderr, "pcregrep version %s\n", pcre_version());
1835    exit(0);    pcregrep_exit(0);
1836    break;    break;
1837    
1838    default:    default:
1839    fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);    fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);
1840    exit(usage(2));    pcregrep_exit(usage(2));
1841    }    }
1842    
1843  return options;  return options;
# Line 1915  for (i = 1; i < argc; i++) Line 2033  for (i = 1; i < argc; i++)
2033    if (argv[i][1] == 0)    if (argv[i][1] == 0)
2034      {      {
2035      if (pattern_filename != NULL || pattern_count > 0) break;      if (pattern_filename != NULL || pattern_count > 0) break;
2036        else exit(usage(2));        else pcregrep_exit(usage(2));
2037      }      }
2038    
2039    /* Handle a long name option, or -- to terminate the options */    /* Handle a long name option, or -- to terminate the options */
# Line 1955  for (i = 1; i < argc; i++) Line 2073  for (i = 1; i < argc; i++)
2073            }            }
2074          else                 /* Special case xxx=data */          else                 /* Special case xxx=data */
2075            {            {
2076            int oplen = equals - op->long_name;            int oplen = (int)(equals - op->long_name);
2077            int arglen = (argequals == NULL)? (int)strlen(arg) : argequals - arg;            int arglen = (argequals == NULL)?
2078                (int)strlen(arg) : (int)(argequals - arg);
2079            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)            if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)
2080              {              {
2081              option_data = arg + arglen;              option_data = arg + arglen;
# Line 1977  for (i = 1; i < argc; i++) Line 2096  for (i = 1; i < argc; i++)
2096          char buff1[24];          char buff1[24];
2097          char buff2[24];          char buff2[24];
2098    
2099          int baselen = opbra - op->long_name;          int baselen = (int)(opbra - op->long_name);
2100          int fulllen = strchr(op->long_name, ')') - op->long_name + 1;          int fulllen = (int)(strchr(op->long_name, ')') - op->long_name + 1);
2101          int arglen = (argequals == NULL || equals == NULL)?          int arglen = (argequals == NULL || equals == NULL)?
2102            (int)strlen(arg) : argequals - arg;            (int)strlen(arg) : (int)(argequals - arg);
2103    
2104          sprintf(buff1, "%.*s", baselen, op->long_name);          sprintf(buff1, "%.*s", baselen, op->long_name);
2105          sprintf(buff2, "%s%.*s", buff1, fulllen - baselen - 2, opbra + 1);          sprintf(buff2, "%s%.*s", buff1, fulllen - baselen - 2, opbra + 1);
# Line 2005  for (i = 1; i < argc; i++) Line 2124  for (i = 1; i < argc; i++)
2124      if (op->one_char == 0)      if (op->one_char == 0)
2125        {        {
2126        fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);        fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);
2127        exit(usage(2));        pcregrep_exit(usage(2));
2128        }        }
2129      }      }
2130    
# Line 2042  for (i = 1; i < argc; i++) Line 2161  for (i = 1; i < argc; i++)
2161      while (*s != 0)      while (*s != 0)
2162        {        {
2163        for (op = optionlist; op->one_char != 0; op++)        for (op = optionlist; op->one_char != 0; op++)
2164          { if (*s == op->one_char) break; }          {
2165            if (*s == op->one_char) break;
2166            }
2167        if (op->one_char == 0)        if (op->one_char == 0)
2168          {          {
2169          fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",          fprintf(stderr, "pcregrep: Unknown option letter '%c' in \"%s\"\n",
2170            *s, argv[i]);            *s, argv[i]);
2171          exit(usage(2));          pcregrep_exit(usage(2));
2172          }          }
2173        if (op->type != OP_NODATA || s[1] == 0)  
2174          {        /* Check for a single-character option that has data: OP_OP_NUMBER
2175          option_data = s+1;        is used for one that either has a numerical number or defaults, i.e. the
2176          break;        data is optional. If a digit follows, there is data; if not, carry on
2177          with other single-character options in the same string. */
2178    
2179          option_data = s+1;
2180          if (op->type == OP_OP_NUMBER)
2181            {
2182            if (isdigit((unsigned char)s[1])) break;
2183          }          }
2184          else   /* Check for end or a dataless option */
2185            {
2186            if (op->type != OP_NODATA || s[1] == 0) break;
2187            }
2188    
2189          /* Handle a single-character option with no data, then loop for the
2190          next character in the string. */
2191    
2192        pcre_options = handle_option(*s++, pcre_options);        pcre_options = handle_option(*s++, pcre_options);
2193        }        }
2194      }      }
# Line 2070  for (i = 1; i < argc; i++) Line 2205  for (i = 1; i < argc; i++)
2205    
2206    /* 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
2207    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
2208    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",
2209    Jeffrey Friedl's special -S debugging option. */    "only-matching", and Jeffrey Friedl's special -S debugging option. */
2210    
2211    if (*option_data == 0 &&    if (*option_data == 0 &&
2212        (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))        (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER))
# Line 2081  for (i = 1; i < argc; i++) Line 2216  for (i = 1; i < argc; i++)
2216        case N_COLOUR:        case N_COLOUR:
2217        colour_option = (char *)"auto";        colour_option = (char *)"auto";
2218        break;        break;
2219    
2220          case 'o':
2221          only_matching = 0;
2222          break;
2223    
2224  #ifdef JFRIEDL_DEBUG  #ifdef JFRIEDL_DEBUG
2225        case 'S':        case 'S':
2226        S_arg = 0;        S_arg = 0;
# Line 2097  for (i = 1; i < argc; i++) Line 2237  for (i = 1; i < argc; i++)
2237      if (i >= argc - 1 || longopwasequals)      if (i >= argc - 1 || longopwasequals)
2238        {        {
2239        fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);        fprintf(stderr, "pcregrep: Data missing after %s\n", argv[i]);
2240        exit(usage(2));        pcregrep_exit(usage(2));
2241        }        }
2242      option_data = argv[++i];      option_data = argv[++i];
2243      }      }
# Line 2122  for (i = 1; i < argc; i++) Line 2262  for (i = 1; i < argc; i++)
2262      {      {
2263      *((char **)op->dataptr) = option_data;      *((char **)op->dataptr) = option_data;
2264      }      }
2265    
2266      /* Avoid the use of strtoul() because SunOS4 doesn't have it. This is used
2267      only for unpicking arguments, so just keep it simple. */
2268    
2269    else    else
2270      {      {
2271      char *endptr;      unsigned long int n = 0;
2272      int n = strtoul(option_data, &endptr, 10);      char *endptr = option_data;
2273        while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++;
2274        while (isdigit((unsigned char)(*endptr)))
2275          n = n * 10 + (int)(*endptr++ - '0');
2276      if (*endptr != 0)      if (*endptr != 0)
2277        {        {
2278        if (longop)        if (longop)
2279          {          {
2280          char *equals = strchr(op->long_name, '=');          char *equals = strchr(op->long_name, '=');
2281          int nlen = (equals == NULL)? (int)strlen(op->long_name) :          int nlen = (equals == NULL)? (int)strlen(op->long_name) :
2282            equals - op->long_name;            (int)(equals - op->long_name);
2283          fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",          fprintf(stderr, "pcregrep: Malformed number \"%s\" after --%.*s\n",
2284            option_data, nlen, op->long_name);            option_data, nlen, op->long_name);
2285          }          }
2286        else        else
2287          fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",          fprintf(stderr, "pcregrep: Malformed number \"%s\" after -%c\n",
2288            option_data, op->one_char);            option_data, op->one_char);
2289        exit(usage(2));        pcregrep_exit(usage(2));
2290        }        }
2291      *((int *)op->dataptr) = n;      *((int *)op->dataptr) = n;
2292      }      }
# Line 2155  if (both_context > 0) Line 2302  if (both_context > 0)
2302    }    }
2303    
2304  /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.  /* Only one of --only-matching, --file-offsets, or --line-offsets is permitted.
2305  However, the latter two set the only_matching flag. */  However, the latter two set only_matching. */
2306    
2307  if ((only_matching && (file_offsets || line_offsets)) ||  if ((only_matching >= 0 && (file_offsets || line_offsets)) ||
2308      (file_offsets && line_offsets))      (file_offsets && line_offsets))
2309    {    {
2310    fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "    fprintf(stderr, "pcregrep: Cannot mix --only-matching, --file-offsets "
2311      "and/or --line-offsets\n");      "and/or --line-offsets\n");
2312    exit(usage(2));    pcregrep_exit(usage(2));
2313    }    }
2314    
2315  if (file_offsets || line_offsets) only_matching = TRUE;  if (file_offsets || line_offsets) only_matching = 0;
2316    
2317  /* 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
2318  LC_ALL environment variable is set, and if so, use it. */  LC_ALL environment variable is set, and if so, use it. */
# Line 2373  for (j = 0; j < pattern_count; j++) Line 2520  for (j = 0; j < pattern_count; j++)
2520      }      }
2521    hint_count++;    hint_count++;
2522    }    }
2523    
2524    /* If --match-limit or --recursion-limit was set, put the value(s) into the
2525    pcre_extra block for each pattern. */
2526    
2527    if (match_limit > 0 || match_limit_recursion > 0)
2528      {
2529      for (j = 0; j < pattern_count; j++)
2530        {
2531        if (hints_list[j] == NULL)
2532          {
2533          hints_list[j] = malloc(sizeof(pcre_extra));
2534          if (hints_list[j] == NULL)
2535            {
2536            fprintf(stderr, "pcregrep: malloc failed\n");
2537            pcregrep_exit(2);
2538            }
2539          }
2540        if (match_limit > 0)
2541          {
2542          hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT;
2543          hints_list[j]->match_limit = match_limit;
2544          }
2545        if (match_limit_recursion > 0)
2546          {
2547          hints_list[j]->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
2548          hints_list[j]->match_limit_recursion = match_limit_recursion;
2549          }
2550        }
2551      }
2552    
2553  /* If there are include or exclude patterns, compile them. */  /* If there are include or exclude patterns, compile them. */
2554    
# Line 2455  if (pattern_list != NULL) Line 2631  if (pattern_list != NULL)
2631    }    }
2632  if (hints_list != NULL)  if (hints_list != NULL)
2633    {    {
2634    for (i = 0; i < hint_count; i++) free(hints_list[i]);    for (i = 0; i < hint_count; i++)
2635        {
2636        if (hints_list[i] != NULL) free(hints_list[i]);
2637        }
2638    free(hints_list);    free(hints_list);
2639    }    }
2640  return rc;  pcregrep_exit(rc);
2641    
2642  EXIT2:  EXIT2:
2643  rc = 2;  rc = 2;

Legend:
Removed from v.515  
changed lines
  Added in v.565

  ViewVC Help
Powered by ViewVC 1.1.5