|
|
1.1 root 1: /*
2: * Grep - search a file for a pattern
3: * This code uses the regexp.c code which is
4: * also used by AWK.
5: */
6:
7: #include <stdio.h>
8: #include <ctype.h>
9: #include "grep.h"
10:
11: #define MAXLINE 400 /* Maximum input line length */
12: #define NEXP 50 /* Maximum number of regular expressions */
13: #define BSIZE BUFSIZ /* Assume block size if buffer size */
14:
15: char line[MAXLINE];
16: struct exps {
17: union {
18: char *u_cp;
19: RE *u_re;
20: } e_un;
21: int (*e_mfun)();
22: } exps[NEXP+1];
23: char usage[] =
24: "Usage: grep [-abchlnsvxy] [-e exp] [-f efile] [expression] [file ...]";
25: char mre[] = "Missing regular expression";
26: char nospace[] = "Out of space for regular expressions";
27: char *fname; /* Current filename */
28:
29: int vflag; /* Reverse sense of match */
30: int cflag; /* Print only count of lines */
31: int lflag; /* Only filenames with matching lines */
32: int nflag; /* precede lines by line number in file */
33: int bflag; /* print block number of match */
34: int sflag; /* No output, only status */
35: int hflag; /* Never print filenames */
36: int xflag; /* Exact match only */
37: int some; /* non-zero if some matches */
38: int outfile; /* Output filename if match flag */
39: int lineno; /* Input line # */
40: unsigned blkno; /* Block number for `-b' */
41: long lmatch; /* Lines matching */
42: int yflag; /* Dual case comparisons */
43:
44: int (*mfun)(); /* Match function */
45: int rematch();
46: int dirmatch();
47: int reinterp();
48: int ematch();
49: int yematch();
50:
51: main(argc, argv)
52: char *argv[];
53: {
54: register RE *rp;
55: register char *cp;
56: register i;
57: struct exps *epp;
58: FILE *fp;
59:
60: mfun = rematch;
61: while (argc>1 && *argv[1]=='-') {
62: for (cp = &argv[1][1]; *cp; cp++)
63: switch (*cp) {
64: case 'a':
65: refull = 1;
66: break;
67:
68: case 'b':
69: bflag = 1;
70: break;
71:
72: case 'c':
73: cflag = 1;
74: break;
75:
76: case 'e':
77: if (argc < 3)
78: err(mre);
79: expsave(argv[2]);
80: argc--;
81: argv++;
82: break;
83:
84: case 'f':
85: if (argc < 3)
86: err("Missing expression filename");
87: if ((fp = fopen(argv[2], "r")) == NULL)
88: err("Cannot open %s", argv[2]);
89: argv++;
90: argc--;
91: while (fgets(line, MAXLINE, fp) != NULL) {
92: i = strlen(line);
93: line[i-1] = '\0';
94: expsave(line);
95: }
96: fclose(fp);
97: break;
98:
99: case 'h':
100: hflag = 1;
101: break;
102:
103: case 'l':
104: lflag = 1;
105: break;
106:
107: case 'n':
108: nflag = 1;
109: break;
110:
111: case 's':
112: sflag = 1;
113: break;
114:
115: case 'v':
116: vflag = 1;
117: break;
118:
119: case 'x':
120: xflag = 1;
121: mfun = dirmatch;
122: break;
123:
124: case 'i':
125: case 'y':
126: redual = 1;
127: yflag = 1;
128: break;
129:
130: default:
131: err(usage);
132: }
133: argv++;
134: argc--;
135: }
136: if (exps[0].e_un.u_cp == NULL) {
137: if (argc-- < 2)
138: err(usage);
139: expsave(argv[1]);
140: argv++;
141: }
142: expsave(NULL);
143: if (!xflag)
144: for (epp = &exps[0]; (cp = epp->e_un.u_cp) != NULL; epp++) {
145: rp = epp->e_un.u_re = reparse(cp, '\0');
146: if (reerror != NULL)
147: err(reerror);
148: for (; rp != NULL; rp = rp->r_next)
149: if (rp->r_op != CONC)
150: break;
151: if (rp != NULL) { /* hard RE */
152: free(cp);
153: epp->e_mfun = reinterp;
154: } else {
155: rp = epp->e_un.u_re;
156: epp->e_un.u_cp = cp;
157: epp->e_mfun = yflag ? yematch : ematch;
158: for ( ; rp!=NULL; rp = rp->r_next) {
159: *cp = rp->r_left.u_ival;
160: cp++;
161: }
162: *cp = '\0';
163: }
164: }
165: if (argc < 3) /* Fewer than 2 files? */
166: hflag = 1;
167: if (argc == 1) {
168: fname = "(stdin)";
169: grep(stdin);
170: } else
171: for (i=1; i<argc; i++) {
172: if ((fp = fopen(argv[i], "r")) == NULL)
173: err("Cannot open %s", argv[i]);
174: fname = argv[i];
175: grep(fp);
176: fclose(fp);
177: }
178: if (cflag)
179: printf("%ld\n", lmatch);
180: exit(!some);
181: }
182:
183: /*
184: * Save regular expression.
185: */
186: expsave(s)
187: register char *s;
188: {
189: static struct exps *epp;
190:
191: if (epp == NULL)
192: epp = &exps[0];
193: if (epp >= &exps[NEXP-1])
194: err("Too many regular expressions");
195: if (s == NULL)
196: epp->e_un.u_cp = NULL;
197: else {
198: if ((epp->e_un.u_cp = malloc(strlen(s)+1)) == NULL)
199: err(nospace);
200: strcpy(epp->e_un.u_cp, s);
201: }
202: epp++;
203: }
204:
205: /*
206: * Called for each input file
207: * to drive the pattern matches.
208: */
209: grep(ifp)
210: FILE *ifp;
211: {
212: register unsigned n;
213: register c;
214: register char *cp;
215:
216: outfile = 0;
217: blkno = 0;
218: n = BSIZE;
219: lineno = 0;
220: for (cp = line; (c = getc(ifp)) != EOF; ) {
221: if (n-- == 0) {
222: n = BSIZE;
223: blkno++;
224: }
225: if (c=='\n' || cp>=&line[MAXLINE-1]) {
226: *cp = '\0';
227: lineno++;
228: (*mfun)(cp = line);
229: } else
230: *cp++ = c;
231: }
232: if (outfile)
233: printf("%s\n", fname);
234: }
235:
236: /*
237: * Called when a match occurred in input
238: */
239: amatch(s)
240: char *s;
241: {
242: some = 1;
243: if (sflag)
244: return;
245: if (!lflag && !cflag) {
246: if (!hflag)
247: printf("%s:", fname);
248: if (bflag)
249: printf("%d:", blkno);
250: else if (nflag)
251: printf("%d:", lineno);
252: printf("%s\n", s);
253: } else if (lflag)
254: outfile = 1;
255: else if (cflag)
256: lmatch++;
257: }
258:
259: /*
260: * try to match each line with all the
261: * regular expressions.
262: * An attempt is made to make expressions
263: * with no metacharacters run faster.
264: */
265: rematch(s)
266: char *s;
267: {
268: register struct exps *epp;
269: register int m;
270:
271: m = 0;
272: for (epp = &exps[0]; epp->e_un.u_re!=NULL && m==0; epp++)
273: if ((*epp->e_mfun)(epp->e_un.u_re, s) != 0)
274: m = 1;
275: if (vflag)
276: m = !m;
277: if (m)
278: amatch(s);
279: return (m);
280: }
281:
282: /*
283: * Direct match function (for `-x' option)
284: */
285: dirmatch(s)
286: char *s;
287: {
288: register struct exps *epp;
289: register m;
290:
291: m = 0;
292: for (epp = &exps[0]; epp->e_un.u_cp!=NULL && !m; epp++)
293: m = yflag ? yseq(epp->e_un.u_cp, s) : seq(epp->e_un.u_cp, s);
294: if (vflag)
295: m = !m;
296: if (m)
297: amatch(s);
298: return (m);
299: }
300:
301: /*
302: * Easy match
303: * For non -y grep.
304: */
305: ematch(p, s)
306: char *p;
307: register char *s;
308: {
309: register char *xp, *xs;
310:
311: do {
312: xp = p;
313: xs = s;
314: while (*xp != '\0') {
315: if (*xs == '\0')
316: return (0);
317: if (*xp != *xs++)
318: break;
319: xp++;
320: }
321: if (*xp == '\0')
322: return (1);
323: } while (*s++ != '\0');
324: return (0);
325: }
326:
327: /*
328: * Version of `ematch' for `-y' option
329: * of grep.
330: */
331: yematch(p, s)
332: char *p;
333: register char *s;
334: {
335: register char *xp, *xs;
336: register int c;
337:
338: do {
339: xp = p;
340: xs = s;
341: while (*xp != '\0') {
342: if (*xs == '\0')
343: return (0);
344: if (islower(*xp) && isupper(*xs))
345: c = tolower(*xs++); else
346: c = *xs++;
347: if (*xp != c)
348: break;
349: xp++;
350: }
351: if (*xp == '\0')
352: return (1);
353: } while (*s++ != '\0');
354: return (0);
355: }
356:
357: /*
358: * String comparison for `-x' option
359: * without `-y' (dual) flag.
360: */
361: seq(p, s)
362: register char *p;
363: register char *s;
364: {
365: while (*s == *p++)
366: if (*s++ == '\0')
367: return (1);
368: return (0);
369: }
370:
371: /*
372: * Version of `seq' for the `-y' option.
373: * First argument is the pattern, the second
374: * is the input string.
375: */
376: yseq(p, s)
377: register char *p;
378: register char *s;
379: {
380: register int c;
381:
382: while ((c = *s++) != '\0') {
383: if (islower(*p) && isupper(c))
384: c = tolower(c);
385: if (c != *p++)
386: return (0);
387: }
388: if (*p != '\0')
389: return (0);
390: return (1);
391: }
392:
393: err(s)
394: {
395: if (!sflag)
396: fprintf(stderr, "grep: %r\n", &s);
397: exit(2);
398: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.