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