grep.c revision 1.1.1.1 1 /*-
2 * Copyright (c) 1999 James Howard and Dag-Erling Codan Smrgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: grep.c,v 1.1.1.1 2004/01/02 14:58:44 cjep Exp $
27 */
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31
32 #include <err.h>
33 #include <errno.h>
34 #include <getopt.h>
35 #include <regex.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "grep.h"
42
43 /* Flags passed to regcomp() and regexec() */
44 int cflags;
45 int eflags = REG_STARTEND;
46
47 int matchall; /* shortcut */
48 int patterns, pattern_sz;
49 char **pattern;
50 regex_t *r_pattern;
51
52 /* For regex errors */
53 char re_error[RE_ERROR_BUF + 1];
54
55 /* Command-line flags */
56 int Aflag; /* -A x: print x lines trailing each match */
57 int Bflag; /* -B x: print x lines leading each match */
58 int Eflag; /* -E: interpret pattern as extended regexp */
59 int Fflag; /* -F: interpret pattern as list of fixed strings */
60 int Gflag; /* -G: interpret pattern as basic regexp */
61 int Hflag; /* -H: if -R, follow explicitly listed symlinks */
62 int Lflag; /* -L: only show names of files with no matches */
63 int Pflag; /* -P: if -R, no symlinks are followed */
64 int Rflag; /* -R: recursively search directory trees */
65 int Sflag; /* -S: if -R, follow all symlinks */
66 int Vflag; /* -V: display version information */
67 int Zflag; /* -Z: decompress input before processing */
68 int aflag; /* -a: only search ascii files */
69 int bflag; /* -b: show block numbers for each match */
70 int cflag; /* -c: only show a count of matching lines */
71 int hflag; /* -h: don't print filename headers */
72 int iflag; /* -i: ignore case */
73 int lflag; /* -l: only show names of files with matches */
74 int nflag; /* -n: show line numbers in front of matching lines */
75 int oflag; /* -o: always print file name */
76 int qflag; /* -q: quiet mode (don't output anything) */
77 int sflag; /* -s: silent mode (ignore errors) */
78 int vflag; /* -v: only show non-matching lines */
79 int wflag; /* -w: pattern must start and end on word boundaries */
80 int xflag; /* -x: pattern must match entire line */
81
82 /* Housekeeping */
83 int first; /* flag whether or not this is our fist match */
84 int tail; /* lines left to print */
85 int lead; /* number of lines in leading context queue */
86
87 char *progname;
88
89 static void
90 usage(void)
91 {
92 fprintf(stderr, "usage: %s %s %s\n",
93 progname,
94 "[-[AB] num] [-CEFGHLPRSVZabchilnoqsvwx]",
95 "[-e patttern] [-f file]");
96 exit(2);
97 }
98
99 static char *optstr = "0123456789A:B:CEFGHLPSRUVZabce:f:hilnoqrsuvwxy";
100
101 struct option long_options[] =
102 {
103 {"basic-regexp", no_argument, NULL, 'G'},
104 {"extended-regexp", no_argument, NULL, 'E'},
105 {"fixed-strings", no_argument, NULL, 'F'},
106 {"after-context", required_argument, NULL, 'A'},
107 {"before-context", required_argument, NULL, 'B'},
108 {"context", optional_argument, NULL, 'C'},
109 {"version", no_argument, NULL, 'V'},
110 {"byte-offset", no_argument, NULL, 'b'},
111 {"count", no_argument, NULL, 'c'},
112 {"regexp", required_argument, NULL, 'e'},
113 {"file", required_argument, NULL, 'f'},
114 {"no-filename", no_argument, NULL, 'h'},
115 {"ignore-case", no_argument, NULL, 'i'},
116 {"files-without-match", no_argument, NULL, 'L'},
117 {"files-with-matches", no_argument, NULL, 'l'},
118 {"line-number", no_argument, NULL, 'n'},
119 {"quiet", no_argument, NULL, 'q'},
120 {"silent", no_argument, NULL, 'q'},
121 {"recursive", no_argument, NULL, 'r'},
122 {"no-messages", no_argument, NULL, 's'},
123 {"text", no_argument, NULL, 'a'},
124 {"revert-match", no_argument, NULL, 'v'},
125 {"word-regexp", no_argument, NULL, 'w'},
126 {"line-regexp", no_argument, NULL, 'x'},
127 {"binary", no_argument, NULL, 'U'},
128 {"unix-byte-offsets", no_argument, NULL, 'u'},
129 {"decompress", no_argument, NULL, 'Z'},
130
131 {NULL, no_argument, NULL, 0}
132 };
133
134
135 static void
136 add_pattern(char *pat, size_t len)
137 {
138 if (len == 0 || matchall) {
139 matchall = 1;
140 return;
141 }
142 if (patterns == pattern_sz) {
143 pattern_sz *= 2;
144 pattern = grep_realloc(pattern, ++pattern_sz);
145 }
146 if (pat[len-1] == '\n')
147 --len;
148 pattern[patterns] = grep_malloc(len+1);
149 strncpy(pattern[patterns], pat, len);
150 pattern[patterns][len] = '\0';
151 ++patterns;
152 }
153
154 static void
155 read_patterns(char *fn)
156 {
157 FILE *f;
158 char *line;
159 size_t len;
160 int nl;
161
162 if ((f = fopen(fn, "r")) == NULL)
163 err(1, "%s", fn);
164 nl = 0;
165 while ((line = fgetln(f, &len)) != NULL) {
166 if (*line == '\n') {
167 ++nl;
168 continue;
169 }
170 if (nl) {
171 matchall = 1;
172 break;
173 }
174 nl = 0;
175 add_pattern(line, len);
176 }
177 if (ferror(f))
178 err(1, "%s", fn);
179 fclose(f);
180 }
181
182 int
183 main(int argc, char *argv[])
184 {
185 char *tmp;
186 int c, i;
187
188 if ((progname = strrchr(*argv, '/')) != NULL)
189 ++progname;
190 else
191 progname = *argv;
192
193 while ((c = getopt_long(argc, argv, optstr,
194 long_options, (int *)NULL)) != -1) {
195 switch (c) {
196 case '0': case '1': case '2': case '3': case '4':
197 case '5': case '6': case '7': case '8': case '9':
198 tmp = argv[optind - 1];
199 if (tmp[0] == '-' && tmp[1] == c && !tmp[2])
200 Aflag = Bflag = strtol(++tmp, (char **)NULL, 10);
201 else
202 Aflag = Bflag = strtol(argv[optind] + 1, (char **)NULL, 10);
203 break;
204 case 'A':
205 Aflag = strtol(optarg, (char **)NULL, 10);
206 break;
207 case 'B':
208 Bflag = strtol(optarg, (char **)NULL, 10);
209 break;
210 case 'C':
211 if (optarg == NULL)
212 Aflag = Bflag = 2;
213 else
214 Aflag = Bflag = strtol(optarg, (char **)NULL, 10);
215 break;
216 case 'E':
217 Eflag++;
218 break;
219 case 'F':
220 Fflag++;
221 break;
222 case 'G':
223 Gflag++;
224 break;
225 case 'H':
226 Hflag++;
227 break;
228 case 'L':
229 lflag = 0;
230 Lflag = qflag = 1;
231 break;
232 case 'P':
233 Pflag++;
234 break;
235 case 'S':
236 Sflag++;
237 break;
238 case 'R':
239 case 'r':
240 Rflag++;
241 oflag++;
242 break;
243 case 'U':
244 case 'u':
245 /* these are here for compatability */
246 break;
247 case 'V':
248 fprintf(stderr, "grep version %u.%u\n", VER_MAJ, VER_MIN);
249 fprintf(stderr, argv[0]);
250 usage();
251 break;
252 case 'Z':
253 Zflag++;
254 break;
255 case 'a':
256 aflag = 1;
257 break;
258 case 'b':
259 bflag = 1;
260 break;
261 case 'c':
262 cflag = 1;
263 break;
264 case 'e':
265 add_pattern(optarg, strlen(optarg));
266 break;
267 case 'f':
268 read_patterns(optarg);
269 break;
270 case 'h':
271 oflag = 0;
272 hflag = 1;
273 break;
274 case 'i':
275 case 'y':
276 cflags |= REG_ICASE;
277 break;
278 case 'l':
279 Lflag = 0;
280 lflag = qflag = 1;
281 break;
282 case 'n':
283 nflag = 1;
284 break;
285 case 'o':
286 hflag = 0;
287 oflag = 1;
288 break;
289 case 'q':
290 qflag = 1;
291 break;
292 case 's':
293 sflag = 1;
294 break;
295 case 'v':
296 vflag = 1;
297 break;
298 case 'w':
299 wflag = 1;
300 break;
301 case 'x':
302 xflag = 1;
303 break;
304 default:
305 usage();
306 }
307 }
308
309 argc -= optind;
310 argv += optind;
311
312 if (argc == 0 && patterns == 0)
313 usage();
314
315 if (patterns == 0) {
316 add_pattern(*argv, strlen(*argv));
317 --argc;
318 ++argv;
319 }
320
321 switch (*progname) {
322 case 'e':
323 Eflag++;
324 break;
325 case 'f':
326 Fflag++;
327 break;
328 case 'g':
329 Gflag++;
330 break;
331 case 'z':
332 Zflag++;
333 break;
334 }
335
336 cflags |= Eflag ? REG_EXTENDED : REG_BASIC;
337 r_pattern = grep_malloc(patterns * sizeof(regex_t));
338 for (i = 0; i < patterns; ++i) {
339 if ((c = regcomp(&r_pattern[i], pattern[i], cflags))) {
340 regerror(c, &r_pattern[i], re_error, RE_ERROR_BUF);
341 errx(1, "%s", re_error);
342 }
343 }
344
345 if ((argc == 0 || argc == 1) && !oflag)
346 hflag = 1;
347
348 if (argc == 0)
349 exit(!procfile(NULL));
350
351 if (Rflag)
352 c = grep_tree(argv);
353 else
354 for (c = 0; argc--; ++argv)
355 c += procfile(*argv);
356
357 exit(!c);
358 }
359