Print this page
3047 grep support for -r would be useful
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/grep/grep.c
+++ new/usr/src/cmd/grep/grep.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 28 /* All Rights Reserved */
29 29
30 30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 31 /* All Rights Reserved */
32 32
33 33 /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */
34 34
35 35 /*
36 36 * grep -- print lines matching (or not matching) a pattern
37 37 *
38 38 * status returns:
39 39 * 0 - ok, and some matches
40 40 * 1 - ok, but no matches
41 41 * 2 - some error
42 42 */
43 43
44 44 #include <sys/types.h>
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
45 45
46 46 #include <ctype.h>
47 47 #include <fcntl.h>
48 48 #include <locale.h>
49 49 #include <memory.h>
50 50 #include <regexpr.h>
51 51 #include <stdio.h>
52 52 #include <stdlib.h>
53 53 #include <string.h>
54 54 #include <unistd.h>
55 +#include <ftw.h>
56 +#include <limits.h>
57 +#include <sys/param.h>
55 58
56 59 static const char *errstr[] = {
57 60 "Range endpoint too large.",
58 61 "Bad number.",
59 62 "``\\digit'' out of range.",
60 63 "No remembered search string.",
61 64 "\\( \\) imbalance.",
62 65 "Too many \\(.",
63 66 "More than 2 numbers given in \\{ \\}.",
64 67 "} expected after \\.",
65 68 "First number exceeds second in \\{ \\}.",
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
66 69 "[ ] imbalance.",
67 70 "Regular expression overflow.",
68 71 "Illegal byte sequence.",
69 72 "Unknown regexp error code!!",
70 73 NULL
71 74 };
72 75
73 76 #define errmsg(msg, arg) (void) fprintf(stderr, gettext(msg), arg)
74 77 #define BLKSIZE 512
75 78 #define GBUFSIZ 8192
79 +#define MAX_DEPTH 1000
76 80
77 81 static int temp;
78 82 static long long lnum;
79 83 static char *linebuf;
80 84 static char *prntbuf = NULL;
81 85 static long fw_lPrntBufLen = 0;
82 86 static int nflag;
83 87 static int bflag;
84 88 static int lflag;
85 89 static int cflag;
90 +static int rflag;
91 +static int Rflag;
86 92 static int vflag;
87 93 static int sflag;
88 94 static int iflag;
89 95 static int wflag;
90 96 static int hflag;
91 97 static int qflag;
92 98 static int errflg;
93 99 static int nfile;
94 100 static long long tln;
95 101 static int nsucc;
102 +static int outfn = 0;
96 103 static int nlflag;
97 104 static char *ptr, *ptrend;
98 105 static char *expbuf;
99 106
100 -static void execute(char *);
107 +static void execute(const char *, int);
101 108 static void regerr(int);
102 -static int succeed(char *);
109 +static void prepare(const char *);
110 +static int recursive(const char *, const struct stat *, int, struct FTW *);
111 +static int succeed(const char *);
103 112
104 113 int
105 114 main(int argc, char **argv)
106 115 {
107 116 int c;
108 117 char *arg;
109 118 extern int optind;
110 119
111 120 (void) setlocale(LC_ALL, "");
112 121 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
113 122 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
114 123 #endif
115 124 (void) textdomain(TEXT_DOMAIN);
116 125
117 - while ((c = getopt(argc, argv, "hqblcnsviyw")) != -1)
126 + while ((c = getopt(argc, argv, "hqblcnRrsviyw")) != -1)
118 127 switch (c) {
119 128 case 'h':
120 129 hflag++;
121 130 break;
122 131 case 'q': /* POSIX: quiet: status only */
123 132 qflag++;
124 133 break;
125 134 case 'v':
126 135 vflag++;
127 136 break;
128 137 case 'c':
129 138 cflag++;
130 139 break;
131 140 case 'n':
132 141 nflag++;
133 142 break;
143 + case 'R':
144 + Rflag++;
145 + /* FALLTHROUGH */
146 + case 'r':
147 + rflag++;
148 + break;
134 149 case 'b':
135 150 bflag++;
136 151 break;
137 152 case 's':
138 153 sflag++;
139 154 break;
140 155 case 'l':
141 156 lflag++;
142 157 break;
143 158 case 'y':
144 159 case 'i':
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
145 160 iflag++;
146 161 break;
147 162 case 'w':
148 163 wflag++;
149 164 break;
150 165 case '?':
151 166 errflg++;
152 167 }
153 168
154 169 if (errflg || (optind >= argc)) {
155 - errmsg("Usage: grep [-c|-l|-q] -hbnsviw pattern file . . .\n",
170 + errmsg("Usage: grep [-c|-l|-q] [-r|-R] -hbnsviw "
171 + "pattern file . . .\n",
156 172 (char *)NULL);
157 173 exit(2);
158 174 }
159 175
160 176 argv = &argv[optind];
161 177 argc -= optind;
162 178 nfile = argc - 1;
163 179
164 180 if (strrchr(*argv, '\n') != NULL)
165 181 regerr(41);
166 182
167 183 if (iflag) {
168 184 for (arg = *argv; *arg != NULL; ++arg)
169 185 *arg = (char)tolower((int)((unsigned char)*arg));
170 186 }
171 187
172 188 if (wflag) {
173 189 unsigned int wordlen;
174 190 char *wordbuf;
175 191
176 192 wordlen = strlen(*argv) + 5; /* '\\' '<' *argv '\\' '>' '\0' */
177 193 if ((wordbuf = malloc(wordlen)) == NULL) {
178 194 errmsg("grep: Out of memory for word\n", (char *)NULL);
179 195 exit(2);
180 196 }
181 197
182 198 (void) strcpy(wordbuf, "\\<");
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
183 199 (void) strcat(wordbuf, *argv);
184 200 (void) strcat(wordbuf, "\\>");
185 201 *argv = wordbuf;
186 202 }
187 203
188 204 expbuf = compile(*argv, (char *)0, (char *)0);
189 205 if (regerrno)
190 206 regerr(regerrno);
191 207
192 208 if (--argc == 0)
193 - execute(NULL);
209 + execute(NULL, 0);
194 210 else
195 211 while (argc-- > 0)
196 - execute(*++argv);
212 + prepare(*++argv);
197 213
198 214 return (nsucc == 2 ? 2 : (nsucc == 0 ? 1 : 0));
199 215 }
200 216
201 217 static void
202 -execute(char *file)
218 +prepare(const char *path)
203 219 {
220 + struct stat st;
221 + int walkflags = FTW_CHDIR;
222 + char *buf = NULL;
223 +
224 + if (rflag) {
225 + if (stat(path, &st) != -1 &&
226 + (st.st_mode & S_IFMT) == S_IFDIR) {
227 + outfn = 1;
228 +
229 + /*
230 + * Add trailing slash if arg
231 + * is directory, to resolve symlinks.
232 + */
233 + if (path[strlen(path) - 1] != '/') {
234 + (void) asprintf(&buf, "%s/", path);
235 + if (buf != NULL)
236 + path = buf;
237 + }
238 +
239 + /*
240 + * Search through subdirs if path is directory.
241 + * Don't follow symlinks if Rflag is not set.
242 + */
243 + if (!Rflag)
244 + walkflags |= FTW_PHYS;
245 +
246 + if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) {
247 + if (!sflag)
248 + errmsg("grep: can't open %s\n", path);
249 + nsucc = 2;
250 + }
251 + return;
252 + }
253 + }
254 + execute(path, 0);
255 +}
256 +
257 +static int
258 +recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw)
259 +{
260 + /*
261 + * process files and follow symlinks if Rflag set.
262 + */
263 + if (info != FTW_F) {
264 + if (!sflag &&
265 + (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
266 + /* report broken symlinks and unreadable files */
267 + errmsg("grep: can't open %s\n", name);
268 + }
269 + return (0);
270 + }
271 +
272 + /* skip devices and pipes if Rflag is not set */
273 + if (!Rflag && !S_ISREG(statp->st_mode))
274 + return (0);
275 +
276 + /* pass offset to relative name from FTW_CHDIR */
277 + execute(name, ftw->base);
278 + return (0);
279 +}
280 +
281 +static void
282 +execute(const char *file, int base)
283 +{
204 284 char *lbuf, *p;
205 285 long count;
206 286 long offset = 0;
207 287 char *next_ptr = NULL;
208 288 long next_count = 0;
209 289
210 290 tln = 0;
211 291
212 292 if (prntbuf == NULL) {
213 293 fw_lPrntBufLen = GBUFSIZ + 1;
214 294 if ((prntbuf = malloc(fw_lPrntBufLen)) == NULL) {
215 295 exit(2); /* out of memory - BAIL */
216 296 }
217 297 if ((linebuf = malloc(fw_lPrntBufLen)) == NULL) {
218 298 exit(2); /* out of memory - BAIL */
219 299 }
220 300 }
221 301
222 302 if (file == NULL)
223 303 temp = 0;
224 - else if ((temp = open(file, O_RDONLY)) == -1) {
304 + else if ((temp = open(file + base, O_RDONLY)) == -1) {
225 305 if (!sflag)
226 306 errmsg("grep: can't open %s\n", file);
227 307 nsucc = 2;
228 308 return;
229 309 }
230 310
231 311 /* read in first block of bytes */
232 312 if ((count = read(temp, prntbuf, GBUFSIZ)) <= 0) {
233 313 (void) close(temp);
234 314
235 315 if (cflag && !qflag) {
236 316 if (nfile > 1 && !hflag && file)
237 317 (void) fprintf(stdout, "%s:", file);
318 + if (!rflag)
238 319 (void) fprintf(stdout, "%lld\n", tln);
239 320 }
240 321 return;
241 322 }
242 323
243 324 lnum = 0;
244 325 ptr = prntbuf;
245 326 for (;;) {
246 327 /* look for next newline */
247 328 if ((ptrend = memchr(ptr + offset, '\n', count)) == NULL) {
248 329 offset += count;
249 330
250 331 /*
251 332 * shift unused data to the beginning of the buffer
252 333 */
253 334 if (ptr > prntbuf) {
254 335 (void) memmove(prntbuf, ptr, offset);
255 336 ptr = prntbuf;
256 337 }
257 338
258 339 /*
259 340 * re-allocate a larger buffer if this one is full
260 341 */
261 342 if (offset + GBUFSIZ > fw_lPrntBufLen) {
262 343 /*
263 344 * allocate a new buffer and preserve the
264 345 * contents...
265 346 */
266 347 fw_lPrntBufLen += GBUFSIZ;
267 348 if ((prntbuf = realloc(prntbuf,
268 349 fw_lPrntBufLen)) == NULL)
269 350 exit(2);
270 351
271 352 /*
272 353 * set up a bigger linebuffer (this is only used
273 354 * for case insensitive operations). Contents do
274 355 * not have to be preserved.
275 356 */
276 357 free(linebuf);
277 358 if ((linebuf = malloc(fw_lPrntBufLen)) == NULL)
278 359 exit(2);
279 360
280 361 ptr = prntbuf;
281 362 }
282 363
283 364 p = prntbuf + offset;
284 365 if ((count = read(temp, p, GBUFSIZ)) > 0)
285 366 continue;
286 367
287 368 if (offset == 0)
288 369 /* end of file already reached */
289 370 break;
290 371
291 372 /* last line of file has no newline */
292 373 ptrend = ptr + offset;
293 374 nlflag = 0;
294 375 } else {
295 376 next_ptr = ptrend + 1;
296 377 next_count = offset + count - (next_ptr - ptr);
297 378 nlflag = 1;
298 379 }
299 380 lnum++;
300 381 *ptrend = '\0';
301 382
302 383 if (iflag) {
303 384 /*
304 385 * Make a lower case copy of the record
305 386 */
306 387 p = ptr;
307 388 for (lbuf = linebuf; p < ptrend; )
308 389 *lbuf++ = (char)tolower((int)
309 390 (unsigned char)*p++);
310 391 *lbuf = '\0';
311 392 lbuf = linebuf;
312 393 } else
313 394 /*
314 395 * Use record as is
315 396 */
316 397 lbuf = ptr;
317 398
318 399 /* lflag only once */
319 400 if ((step(lbuf, expbuf) ^ vflag) && succeed(file) == 1)
320 401 break;
321 402
↓ open down ↓ |
74 lines elided |
↑ open up ↑ |
322 403 if (!nlflag)
323 404 break;
324 405
325 406 ptr = next_ptr;
326 407 count = next_count;
327 408 offset = 0;
328 409 }
329 410 (void) close(temp);
330 411
331 412 if (cflag && !qflag) {
332 - if (nfile > 1 && !hflag && file)
413 + if (!hflag && file && (nfile > 1 ||
414 + (rflag && outfn)))
333 415 (void) fprintf(stdout, "%s:", file);
334 416 (void) fprintf(stdout, "%lld\n", tln);
335 417 }
336 418 }
337 419
338 420 static int
339 -succeed(char *f)
421 +succeed(const char *f)
340 422 {
341 423 int nchars;
342 424 nsucc = (nsucc == 2) ? 2 : 1;
343 425
344 426 if (f == NULL)
345 427 f = "<stdin>";
346 428
347 429 if (qflag) {
348 430 /* no need to continue */
349 431 return (1);
350 432 }
351 433
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
352 434 if (cflag) {
353 435 tln++;
354 436 return (0);
355 437 }
356 438
357 439 if (lflag) {
358 440 (void) fprintf(stdout, "%s\n", f);
359 441 return (1);
360 442 }
361 443
362 - if (nfile > 1 && !hflag)
444 + if (!hflag && (nfile > 1 || (rflag && outfn))) {
363 445 /* print filename */
364 446 (void) fprintf(stdout, "%s:", f);
447 + }
365 448
366 449 if (bflag)
367 450 /* print block number */
368 451 (void) fprintf(stdout, "%lld:", (offset_t)
369 452 ((lseek(temp, (off_t)0, SEEK_CUR) - 1) / BLKSIZE));
370 453
371 454 if (nflag)
372 455 /* print line number */
373 456 (void) fprintf(stdout, "%lld:", lnum);
374 457
375 458 if (nlflag) {
376 459 /* newline at end of line */
377 460 *ptrend = '\n';
378 461 nchars = ptrend - ptr + 1;
379 462 } else {
380 463 /* don't write sentinel \0 */
381 464 nchars = ptrend - ptr;
382 465 }
383 466
384 467 (void) fwrite(ptr, 1, nchars, stdout);
385 468 return (0);
386 469 }
387 470
388 471 static void
389 472 regerr(int err)
390 473 {
391 474 errmsg("grep: RE error %d: ", err);
392 475 switch (err) {
393 476 case 11:
394 477 err = 0;
395 478 break;
396 479 case 16:
397 480 err = 1;
398 481 break;
399 482 case 25:
400 483 err = 2;
401 484 break;
402 485 case 41:
403 486 err = 3;
404 487 break;
405 488 case 42:
406 489 err = 4;
407 490 break;
408 491 case 43:
409 492 err = 5;
410 493 break;
411 494 case 44:
412 495 err = 6;
413 496 break;
414 497 case 45:
415 498 err = 7;
416 499 break;
417 500 case 46:
418 501 err = 8;
419 502 break;
420 503 case 49:
421 504 err = 9;
422 505 break;
423 506 case 50:
424 507 err = 10;
425 508 break;
426 509 case 67:
427 510 err = 11;
428 511 break;
429 512 default:
430 513 err = 12;
431 514 break;
432 515 }
433 516
434 517 errmsg("%s\n", gettext(errstr[err]));
435 518 exit(2);
436 519 }
↓ open down ↓ |
62 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX