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