650 grep support for -q would be useful
[unleashed.git] / usr / src / cmd / grep / grep.c
blob62a4527529e16cd7637cee0accdde6049a03a065
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
33 /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */
36 * grep -- print lines matching (or not matching) a pattern
38 * status returns:
39 * 0 - ok, and some matches
40 * 1 - ok, but no matches
41 * 2 - some error
44 #include <sys/types.h>
46 #include <ctype.h>
47 #include <fcntl.h>
48 #include <locale.h>
49 #include <memory.h>
50 #include <regexpr.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
56 static const char *errstr[] = {
57 "Range endpoint too large.",
58 "Bad number.",
59 "``\\digit'' out of range.",
60 "No remembered search string.",
61 "\\( \\) imbalance.",
62 "Too many \\(.",
63 "More than 2 numbers given in \\{ \\}.",
64 "} expected after \\.",
65 "First number exceeds second in \\{ \\}.",
66 "[ ] imbalance.",
67 "Regular expression overflow.",
68 "Illegal byte sequence.",
69 "Unknown regexp error code!!",
70 NULL
73 #define errmsg(msg, arg) (void) fprintf(stderr, gettext(msg), arg)
74 #define BLKSIZE 512
75 #define GBUFSIZ 8192
77 static int temp;
78 static long long lnum;
79 static char *linebuf;
80 static char *prntbuf = NULL;
81 static long fw_lPrntBufLen = 0;
82 static int nflag;
83 static int bflag;
84 static int lflag;
85 static int cflag;
86 static int vflag;
87 static int sflag;
88 static int iflag;
89 static int wflag;
90 static int hflag;
91 static int qflag;
92 static int errflg;
93 static int nfile;
94 static long long tln;
95 static int nsucc;
96 static int nlflag;
97 static char *ptr, *ptrend;
98 static char *expbuf;
100 static void execute(char *);
101 static void regerr(int);
102 static int succeed(char *);
105 main(int argc, char **argv)
107 int c;
108 char *arg;
109 extern int optind;
111 (void) setlocale(LC_ALL, "");
112 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
113 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
114 #endif
115 (void) textdomain(TEXT_DOMAIN);
117 while ((c = getopt(argc, argv, "hqblcnsviyw")) != -1)
118 switch (c) {
119 case 'h':
120 hflag++;
121 break;
122 case 'q': /* POSIX: quiet: status only */
123 qflag++;
124 break;
125 case 'v':
126 vflag++;
127 break;
128 case 'c':
129 cflag++;
130 break;
131 case 'n':
132 nflag++;
133 break;
134 case 'b':
135 bflag++;
136 break;
137 case 's':
138 sflag++;
139 break;
140 case 'l':
141 lflag++;
142 break;
143 case 'y':
144 case 'i':
145 iflag++;
146 break;
147 case 'w':
148 wflag++;
149 break;
150 case '?':
151 errflg++;
154 if (errflg || (optind >= argc)) {
155 errmsg("Usage: grep [-c|-l|-q] -hbnsviw pattern file . . .\n",
156 (char *)NULL);
157 exit(2);
160 argv = &argv[optind];
161 argc -= optind;
162 nfile = argc - 1;
164 if (strrchr(*argv, '\n') != NULL)
165 regerr(41);
167 if (iflag) {
168 for (arg = *argv; *arg != NULL; ++arg)
169 *arg = (char)tolower((int)((unsigned char)*arg));
172 if (wflag) {
173 unsigned int wordlen;
174 char *wordbuf;
176 wordlen = strlen(*argv) + 5; /* '\\' '<' *argv '\\' '>' '\0' */
177 if ((wordbuf = malloc(wordlen)) == NULL) {
178 errmsg("grep: Out of memory for word\n", (char *)NULL);
179 exit(2);
182 (void) strcpy(wordbuf, "\\<");
183 (void) strcat(wordbuf, *argv);
184 (void) strcat(wordbuf, "\\>");
185 *argv = wordbuf;
188 expbuf = compile(*argv, (char *)0, (char *)0);
189 if (regerrno)
190 regerr(regerrno);
192 if (--argc == 0)
193 execute(NULL);
194 else
195 while (argc-- > 0)
196 execute(*++argv);
198 return (nsucc == 2 ? 2 : (nsucc == 0 ? 1 : 0));
201 static void
202 execute(char *file)
204 char *lbuf, *p;
205 long count;
206 long offset = 0;
207 char *next_ptr = NULL;
208 long next_count = 0;
210 tln = 0;
212 if (prntbuf == NULL) {
213 fw_lPrntBufLen = GBUFSIZ + 1;
214 if ((prntbuf = malloc(fw_lPrntBufLen)) == NULL) {
215 exit(2); /* out of memory - BAIL */
217 if ((linebuf = malloc(fw_lPrntBufLen)) == NULL) {
218 exit(2); /* out of memory - BAIL */
222 if (file == NULL)
223 temp = 0;
224 else if ((temp = open(file, O_RDONLY)) == -1) {
225 if (!sflag)
226 errmsg("grep: can't open %s\n", file);
227 nsucc = 2;
228 return;
231 /* read in first block of bytes */
232 if ((count = read(temp, prntbuf, GBUFSIZ)) <= 0) {
233 (void) close(temp);
235 if (cflag && !qflag) {
236 if (nfile > 1 && !hflag && file)
237 (void) fprintf(stdout, "%s:", file);
238 (void) fprintf(stdout, "%lld\n", tln);
240 return;
243 lnum = 0;
244 ptr = prntbuf;
245 for (;;) {
246 /* look for next newline */
247 if ((ptrend = memchr(ptr + offset, '\n', count)) == NULL) {
248 offset += count;
251 * shift unused data to the beginning of the buffer
253 if (ptr > prntbuf) {
254 (void) memmove(prntbuf, ptr, offset);
255 ptr = prntbuf;
259 * re-allocate a larger buffer if this one is full
261 if (offset + GBUFSIZ > fw_lPrntBufLen) {
263 * allocate a new buffer and preserve the
264 * contents...
266 fw_lPrntBufLen += GBUFSIZ;
267 if ((prntbuf = realloc(prntbuf,
268 fw_lPrntBufLen)) == NULL)
269 exit(2);
272 * set up a bigger linebuffer (this is only used
273 * for case insensitive operations). Contents do
274 * not have to be preserved.
276 free(linebuf);
277 if ((linebuf = malloc(fw_lPrntBufLen)) == NULL)
278 exit(2);
280 ptr = prntbuf;
283 p = prntbuf + offset;
284 if ((count = read(temp, p, GBUFSIZ)) > 0)
285 continue;
287 if (offset == 0)
288 /* end of file already reached */
289 break;
291 /* last line of file has no newline */
292 ptrend = ptr + offset;
293 nlflag = 0;
294 } else {
295 next_ptr = ptrend + 1;
296 next_count = offset + count - (next_ptr - ptr);
297 nlflag = 1;
299 lnum++;
300 *ptrend = '\0';
302 if (iflag) {
304 * Make a lower case copy of the record
306 p = ptr;
307 for (lbuf = linebuf; p < ptrend; )
308 *lbuf++ = (char)tolower((int)
309 (unsigned char)*p++);
310 *lbuf = '\0';
311 lbuf = linebuf;
312 } else
314 * Use record as is
316 lbuf = ptr;
318 /* lflag only once */
319 if ((step(lbuf, expbuf) ^ vflag) && succeed(file) == 1)
320 break;
322 if (!nlflag)
323 break;
325 ptr = next_ptr;
326 count = next_count;
327 offset = 0;
329 (void) close(temp);
331 if (cflag && !qflag) {
332 if (nfile > 1 && !hflag && file)
333 (void) fprintf(stdout, "%s:", file);
334 (void) fprintf(stdout, "%lld\n", tln);
338 static int
339 succeed(char *f)
341 int nchars;
342 nsucc = (nsucc == 2) ? 2 : 1;
344 if (f == NULL)
345 f = "<stdin>";
347 if (qflag) {
348 /* no need to continue */
349 return (1);
352 if (cflag) {
353 tln++;
354 return (0);
357 if (lflag) {
358 (void) fprintf(stdout, "%s\n", f);
359 return (1);
362 if (nfile > 1 && !hflag)
363 /* print filename */
364 (void) fprintf(stdout, "%s:", f);
366 if (bflag)
367 /* print block number */
368 (void) fprintf(stdout, "%lld:", (offset_t)
369 ((lseek(temp, (off_t)0, SEEK_CUR) - 1) / BLKSIZE));
371 if (nflag)
372 /* print line number */
373 (void) fprintf(stdout, "%lld:", lnum);
375 if (nlflag) {
376 /* newline at end of line */
377 *ptrend = '\n';
378 nchars = ptrend - ptr + 1;
379 } else {
380 /* don't write sentinel \0 */
381 nchars = ptrend - ptr;
384 (void) fwrite(ptr, 1, nchars, stdout);
385 return (0);
388 static void
389 regerr(int err)
391 errmsg("grep: RE error %d: ", err);
392 switch (err) {
393 case 11:
394 err = 0;
395 break;
396 case 16:
397 err = 1;
398 break;
399 case 25:
400 err = 2;
401 break;
402 case 41:
403 err = 3;
404 break;
405 case 42:
406 err = 4;
407 break;
408 case 43:
409 err = 5;
410 break;
411 case 44:
412 err = 6;
413 break;
414 case 45:
415 err = 7;
416 break;
417 case 46:
418 err = 8;
419 break;
420 case 49:
421 err = 9;
422 break;
423 case 50:
424 err = 10;
425 break;
426 case 67:
427 err = 11;
428 break;
429 default:
430 err = 12;
431 break;
434 errmsg("%s\n", gettext(errstr[err]));
435 exit(2);