1/*************************************************
2*               PCRE grep program                *
3*************************************************/
4
5#include <stdio.h>
6#include <string.h>
7#include <stdlib.h>
8#include <errno.h>
9#include "config.h"
10#include "pcre.h"
11
12#define FALSE 0
13#define TRUE 1
14
15typedef int BOOL;
16
17
18
19/*************************************************
20*               Global variables                 *
21*************************************************/
22
23static pcre *pattern;
24static pcre_extra *hints;
25
26static BOOL count_only = FALSE;
27static BOOL filenames_only = FALSE;
28static BOOL invert = FALSE;
29static BOOL number = FALSE;
30static BOOL silent = FALSE;
31static BOOL whole_lines = FALSE;
32
33
34
35#if ! HAVE_STRERROR
36/*************************************************
37*     Provide strerror() for non-ANSI libraries  *
38*************************************************/
39
40/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror()
41in their libraries, but can provide the same facility by this simple
42alternative function. */
43
44extern int   sys_nerr;
45extern char *sys_errlist[];
46
47char *
48strerror(int n)
49{
50if (n < 0 || n >= sys_nerr) return "unknown error number";
51return sys_errlist[n];
52}
53#endif /* HAVE_STRERROR */
54
55
56
57/*************************************************
58*              Grep an individual file           *
59*************************************************/
60
61static int
62pgrep(FILE *in, char *name)
63{
64int rc = 1;
65int linenumber = 0;
66int count = 0;
67int offsets[99];
68char buffer[BUFSIZ];
69
70while (fgets(buffer, sizeof(buffer), in) != NULL)
71  {
72  BOOL match;
73  int length = (int)strlen(buffer);
74  if (length > 0 && buffer[length-1] == '\n') buffer[--length] = 0;
75  linenumber++;
76
77  match = pcre_exec(pattern, hints, buffer, length, 0, 0, offsets, 99) >= 0;
78  if (match && whole_lines && offsets[1] != length) match = FALSE;
79
80  if (match != invert)
81    {
82    if (count_only) count++;
83
84    else if (filenames_only)
85      {
86      fprintf(stdout, "%s\n", (name == NULL)? "<stdin>" : name);
87      return 0;
88      }
89
90    else if (silent) return 0;
91
92    else
93      {
94      if (name != NULL) fprintf(stdout, "%s:", name);
95      if (number) fprintf(stdout, "%d:", linenumber);
96      fprintf(stdout, "%s\n", buffer);
97      }
98
99    rc = 0;
100    }
101  }
102
103if (count_only)
104  {
105  if (name != NULL) fprintf(stdout, "%s:", name);
106  fprintf(stdout, "%d\n", count);
107  }
108
109return rc;
110}
111
112
113
114
115/*************************************************
116*                Usage function                  *
117*************************************************/
118
119static int
120usage(int rc)
121{
122fprintf(stderr, "Usage: pgrep [-Vchilnsvx] pattern [file] ...\n");
123return rc;
124}
125
126
127
128
129/*************************************************
130*                Main program                    *
131*************************************************/
132
133int
134main(int argc, char **argv)
135{
136int i;
137int rc = 1;
138int options = 0;
139int errptr;
140const char *error;
141BOOL filenames = TRUE;
142
143/* Process the options */
144
145for (i = 1; i < argc; i++)
146  {
147  char *s;
148  if (argv[i][0] != '-') break;
149  s = argv[i] + 1;
150  while (*s != 0)
151    {
152    switch (*s++)
153      {
154      case 'c': count_only = TRUE; break;
155      case 'h': filenames = FALSE; break;
156      case 'i': options |= PCRE_CASELESS; break;
157      case 'l': filenames_only = TRUE;
158      case 'n': number = TRUE; break;
159      case 's': silent = TRUE; break;
160      case 'v': invert = TRUE; break;
161      case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break;
162
163      case 'V':
164      fprintf(stderr, "PCRE version %s\n", pcre_version());
165      break;
166
167      default:
168      fprintf(stderr, "pgrep: unknown option %c\n", s[-1]);
169      return usage(2);
170      }
171    }
172  }
173
174/* There must be at least a regexp argument */
175
176if (i >= argc) return usage(0);
177
178/* Compile the regular expression. */
179
180pattern = pcre_compile(argv[i++], options, &error, &errptr, NULL);
181if (pattern == NULL)
182  {
183  fprintf(stderr, "pgrep: error in regex at offset %d: %s\n", errptr, error);
184  return 2;
185  }
186
187/* Study the regular expression, as we will be running it may times */
188
189hints = pcre_study(pattern, 0, &error);
190if (error != NULL)
191  {
192  fprintf(stderr, "pgrep: error while studing regex: %s\n", error);
193  return 2;
194  }
195
196/* If there are no further arguments, do the business on stdin and exit */
197
198if (i >= argc) return pgrep(stdin, NULL);
199
200/* Otherwise, work through the remaining arguments as files. If there is only
201one, don't give its name on the output. */
202
203if (i == argc - 1) filenames = FALSE;
204if (filenames_only) filenames = TRUE;
205
206for (; i < argc; i++)
207  {
208  FILE *in = fopen(argv[i], "r");
209  if (in == NULL)
210    {
211    fprintf(stderr, "%s: failed to open: %s\n", argv[i], strerror(errno));
212    rc = 2;
213    }
214  else
215    {
216    int frc = pgrep(in, filenames? argv[i] : NULL);
217    if (frc == 0 && rc == 1) rc = 0;
218    fclose(in);
219    }
220  }
221
222return rc;
223}
224
225/* End */
226