Annotation of src/usr.bin/grep/grep.c, Revision 1.4
1.1 deraadt 1: /*-
1.3 deraadt 2: * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
3: * All rights reserved.
1.1 deraadt 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.
1.3 deraadt 25: *
1.4 ! deraadt 26: * $Id: grep.c,v 1.3 2003/06/22 22:20:07 deraadt Exp $
1.1 deraadt 27: */
28:
1.3 deraadt 29: #include <sys/types.h>
30: #include <sys/stat.h>
1.1 deraadt 31:
1.3 deraadt 32: #include <err.h>
33: #include <errno.h>
34: #include <getopt.h>
35: #include <regex.h>
1.1 deraadt 36: #include <stdio.h>
37: #include <stdlib.h>
1.3 deraadt 38: #include <string.h>
1.1 deraadt 39: #include <unistd.h>
40:
1.3 deraadt 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:
1.1 deraadt 134:
1.3 deraadt 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: }
1.1 deraadt 153:
1.3 deraadt 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: }
1.1 deraadt 181:
182: int
1.3 deraadt 183: main(int argc, char *argv[])
1.1 deraadt 184: {
1.3 deraadt 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);
1.1 deraadt 215: break;
216: case 'E':
1.3 deraadt 217: Eflag++;
1.1 deraadt 218: break;
219: case 'F':
1.3 deraadt 220: Fflag++;
221: break;
222: case 'G':
223: Gflag++;
1.1 deraadt 224: break;
225: case 'H':
1.3 deraadt 226: Hflag++;
1.1 deraadt 227: break;
228: case 'L':
1.3 deraadt 229: lflag = 0;
230: Lflag = qflag = 1;
1.1 deraadt 231: break;
232: case 'P':
1.3 deraadt 233: Pflag++;
234: break;
235: case 'S':
236: Sflag++;
1.1 deraadt 237: break;
238: case 'R':
1.3 deraadt 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();
1.1 deraadt 251: break;
1.3 deraadt 252: case 'Z':
253: Zflag++;
1.1 deraadt 254: break;
255: case 'a':
1.3 deraadt 256: aflag = 1;
1.1 deraadt 257: break;
258: case 'b':
1.3 deraadt 259: bflag = 1;
1.1 deraadt 260: break;
261: case 'c':
1.3 deraadt 262: cflag = 1;
1.1 deraadt 263: break;
264: case 'e':
1.3 deraadt 265: add_pattern(optarg, strlen(optarg));
1.1 deraadt 266: break;
267: case 'f':
1.3 deraadt 268: read_patterns(optarg);
1.1 deraadt 269: break;
270: case 'h':
1.3 deraadt 271: oflag = 0;
272: hflag = 1;
1.1 deraadt 273: break;
274: case 'i':
1.3 deraadt 275: case 'y':
1.1 deraadt 276: cflags |= REG_ICASE;
277: break;
278: case 'l':
1.3 deraadt 279: Lflag = 0;
280: lflag = qflag = 1;
1.1 deraadt 281: break;
282: case 'n':
1.3 deraadt 283: nflag = 1;
284: break;
285: case 'o':
286: hflag = 0;
287: oflag = 1;
1.1 deraadt 288: break;
289: case 'q':
1.3 deraadt 290: qflag = 1;
1.1 deraadt 291: break;
292: case 's':
1.3 deraadt 293: sflag = 1;
1.1 deraadt 294: break;
295: case 'v':
1.3 deraadt 296: vflag = 1;
1.1 deraadt 297: break;
298: case 'w':
1.3 deraadt 299: wflag = 1;
1.1 deraadt 300: break;
301: case 'x':
1.3 deraadt 302: xflag = 1;
1.1 deraadt 303: break;
304: default:
305: usage();
306: }
307: }
308:
1.3 deraadt 309: argc -= optind;
310: argv += optind;
311:
312: if (argc == 0 && patterns == 0)
1.1 deraadt 313: usage();
314:
1.3 deraadt 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++;
1.4 ! deraadt 333: switch(progname[1]) {
! 334: case 'e':
! 335: Eflag++;
! 336: break;
! 337: case 'f':
! 338: Fflag++;
! 339: break;
! 340: case 'g':
! 341: Gflag++;
! 342: break;
! 343: }
1.3 deraadt 344: break;
345: }
346:
347: cflags |= Eflag ? REG_EXTENDED : REG_BASIC;
348: r_pattern = grep_malloc(patterns * sizeof(regex_t));
349: for (i = 0; i < patterns; ++i) {
350: if ((c = regcomp(&r_pattern[i], pattern[i], cflags))) {
351: regerror(c, &r_pattern[i], re_error, RE_ERROR_BUF);
352: errx(1, "%s", re_error);
1.1 deraadt 353: }
354: }
355:
1.3 deraadt 356: if ((argc == 0 || argc == 1) && !oflag)
357: hflag = 1;
1.1 deraadt 358:
1.3 deraadt 359: if (argc == 0)
360: exit(!procfile(NULL));
361:
362: if (Rflag)
363: c = grep_tree(argv);
1.1 deraadt 364: else
1.3 deraadt 365: for (c = 0; argc--; ++argv)
366: c += procfile(*argv);
1.1 deraadt 367:
1.3 deraadt 368: exit(!c);
1.1 deraadt 369: }