Print this page
4701 would like grep context options (-A, -B, -C)
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/grep_xpg4/grep.c
+++ new/usr/src/cmd/grep_xpg4/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 2004 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * grep - pattern matching program - combined grep, egrep, and fgrep.
29 29 * Based on MKS grep command, with XCU & Solaris mods.
30 30 */
31 31
32 32 /*
33 33 * Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved.
34 34 *
35 35 */
36 36
37 37 /* Copyright 2012 Nexenta Systems, Inc. All rights reserved. */
38 38
39 39 /*
40 40 * Copyright 2013 Damian Bogel. All rights reserved.
41 41 */
42 42
43 43 #include <string.h>
44 44 #include <stdlib.h>
45 45 #include <ctype.h>
46 46 #include <stdarg.h>
47 47 #include <regex.h>
48 48 #include <limits.h>
49 49 #include <sys/types.h>
50 50 #include <sys/stat.h>
51 51 #include <fcntl.h>
52 52 #include <stdio.h>
53 53 #include <locale.h>
54 54 #include <wchar.h>
55 55 #include <errno.h>
56 56 #include <unistd.h>
↓ open down ↓ |
56 lines elided |
↑ open up ↑ |
57 57 #include <wctype.h>
58 58 #include <ftw.h>
59 59 #include <sys/param.h>
60 60
61 61 #define STDIN_FILENAME gettext("(standard input)")
62 62
63 63 #define BSIZE 512 /* Size of block for -b */
64 64 #define BUFSIZE 8192 /* Input buffer size */
65 65 #define MAX_DEPTH 1000 /* how deep to recurse */
66 66
67 +#define AFTER 1 /* 'After' Context */
68 +#define BEFORE 2 /* 'Before' Context */
69 +#define CONTEXT (AFTER|BEFORE) /* Full Context */
70 +
67 71 #define M_CSETSIZE 256 /* singlebyte chars */
68 72 static int bmglen; /* length of BMG pattern */
69 73 static char *bmgpat; /* BMG pattern */
70 74 static int bmgtab[M_CSETSIZE]; /* BMG delta1 table */
71 75
72 76 typedef struct _PATTERN {
73 77 char *pattern; /* original pattern */
74 78 wchar_t *wpattern; /* wide, lowercased pattern */
75 79 struct _PATTERN *next;
76 80 regex_t re; /* compiled pattern */
77 81 } PATTERN;
78 82
79 83 static PATTERN *patterns;
80 84 static char errstr[128]; /* regerror string buffer */
81 85 static int regflags = 0; /* regcomp options */
82 86 static int matched = 0; /* return of the grep() */
83 87 static int errors = 0; /* count of errors */
84 88 static uchar_t fgrep = 0; /* Invoked as fgrep */
85 89 static uchar_t egrep = 0; /* Invoked as egrep */
86 90 static uchar_t nvflag = 1; /* Print matching lines */
87 91 static uchar_t cflag; /* Count of matches */
88 92 static uchar_t iflag; /* Case insensitve matching */
89 93 static uchar_t Hflag; /* Precede lines by file name */
90 94 static uchar_t hflag; /* Supress printing of filename */
91 95 static uchar_t lflag; /* Print file names of matches */
92 96 static uchar_t nflag; /* Precede lines by line number */
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
93 97 static uchar_t rflag; /* Search directories recursively */
94 98 static uchar_t bflag; /* Preccede matches by block number */
95 99 static uchar_t sflag; /* Suppress file error messages */
96 100 static uchar_t qflag; /* Suppress standard output */
97 101 static uchar_t wflag; /* Search for expression as a word */
98 102 static uchar_t xflag; /* Anchoring */
99 103 static uchar_t Eflag; /* Egrep or -E flag */
100 104 static uchar_t Fflag; /* Fgrep or -F flag */
101 105 static uchar_t Rflag; /* Like rflag, but follow symlinks */
102 106 static uchar_t outfn; /* Put out file name */
107 +static uchar_t conflag; /* show context of matches */
103 108 static char *cmdname;
104 109
105 110 static int use_wchar, use_bmg, mblocale;
106 111
107 -static size_t outbuflen, prntbuflen;
108 -static char *prntbuf;
112 +static size_t outbuflen, prntbuflen, conbuflen;
113 +static unsigned long conalen, conblen, conmatches;
114 +static char *prntbuf, *conbuf;
109 115 static wchar_t *outline;
110 116
111 117 static void addfile(const char *fn);
112 118 static void addpattern(char *s);
113 119 static void fixpatterns(void);
114 120 static void usage(void);
115 121 static int grep(int, const char *);
116 122 static void bmgcomp(char *, int);
117 123 static char *bmgexec(char *, char *);
118 124 static int recursive(const char *, const struct stat *, int, struct FTW *);
119 125 static void process_path(const char *);
120 126 static void process_file(const char *, int);
121 127
122 128 /*
123 129 * mainline for grep
124 130 */
125 131 int
126 132 main(int argc, char **argv)
127 133 {
128 - char *ap;
134 + char *ap, *test;
129 135 int c;
130 136 int fflag = 0;
131 137 int i, n_pattern = 0, n_file = 0;
132 138 char **pattern_list = NULL;
133 139 char **file_list = NULL;
134 140
135 141 (void) setlocale(LC_ALL, "");
136 142 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
137 143 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
138 144 #endif
139 145 (void) textdomain(TEXT_DOMAIN);
140 146
141 147 /*
142 148 * true if this is running on the multibyte locale
143 149 */
144 150 mblocale = (MB_CUR_MAX > 1);
145 151 /*
146 152 * Skip leading slashes
147 153 */
148 154 cmdname = argv[0];
149 155 if (ap = strrchr(cmdname, '/'))
150 156 cmdname = ap + 1;
151 157
152 158 ap = cmdname;
153 159 /*
154 160 * Detect egrep/fgrep via command name, map to -E and -F options.
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
155 161 */
156 162 if (*ap == 'e' || *ap == 'E') {
157 163 regflags |= REG_EXTENDED;
158 164 egrep++;
159 165 } else {
160 166 if (*ap == 'f' || *ap == 'F') {
161 167 fgrep++;
162 168 }
163 169 }
164 170
165 - while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIR")) != EOF) {
171 + /* check for non-standard "-line-count" option */
172 + for (i = 1; i < argc; i++) {
173 + if (strcmp(argv[i], "--") == 0)
174 + break;
175 +
176 + if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
177 + if (strlen(&argv[i][1]) !=
178 + strspn(&argv[i][1], "0123456789")) {
179 + (void) fprintf(stderr, gettext(
180 + "%s: Bad number flag\n"), argv[0]);
181 + usage();
182 + }
183 +
184 + conalen = conblen = strtoul(&argv[i][1], (char **)NULL,
185 + 10);
186 +
187 + /* isdigit() check prevents negative arguments */
188 + if (conalen >= ULONG_MAX) {
189 + (void) fprintf(stderr, gettext(
190 + "%s: Bad context argument\n"), argv[0]);
191 + }
192 +
193 + if (conalen)
194 + conflag = CONTEXT;
195 +
196 + while (i < argc) {
197 + argv[i] = argv[i + 1];
198 + i++;
199 + }
200 + argc--;
201 + }
202 + }
203 +
204 + while ((c = getopt(argc, argv, "vwchHilnrbse:f:qxEFIRA:B:C:")) != EOF) {
205 + unsigned long tval;
166 206 switch (c) {
167 207 case 'v': /* POSIX: negate matches */
168 208 nvflag = 0;
169 209 break;
170 210
171 211 case 'c': /* POSIX: write count */
172 212 cflag++;
173 213 break;
174 214
175 215 case 'i': /* POSIX: ignore case */
176 216 iflag++;
177 217 regflags |= REG_ICASE;
178 218 break;
179 219
180 220 case 'l': /* POSIX: Write filenames only */
181 221 lflag++;
182 222 break;
183 223
184 224 case 'n': /* POSIX: Write line numbers */
185 225 nflag++;
186 226 break;
187 227
188 228 case 'r': /* Solaris: search recursively */
189 229 rflag++;
190 230 break;
191 231
192 232 case 'b': /* Solaris: Write file block numbers */
193 233 bflag++;
194 234 break;
195 235
196 236 case 's': /* POSIX: No error msgs for files */
197 237 sflag++;
198 238 break;
199 239
200 240 case 'e': /* POSIX: pattern list */
201 241 n_pattern++;
202 242 pattern_list = realloc(pattern_list,
203 243 sizeof (char *) * n_pattern);
204 244 if (pattern_list == NULL) {
205 245 (void) fprintf(stderr,
206 246 gettext("%s: out of memory\n"),
207 247 cmdname);
208 248 exit(2);
209 249 }
210 250 *(pattern_list + n_pattern - 1) = optarg;
211 251 break;
212 252
213 253 case 'f': /* POSIX: pattern file */
214 254 fflag = 1;
215 255 n_file++;
216 256 file_list = realloc(file_list,
217 257 sizeof (char *) * n_file);
218 258 if (file_list == NULL) {
219 259 (void) fprintf(stderr,
220 260 gettext("%s: out of memory\n"),
221 261 cmdname);
222 262 exit(2);
223 263 }
224 264 *(file_list + n_file - 1) = optarg;
225 265 break;
226 266
227 267 /* based on options order h or H is set as in GNU grep */
228 268 case 'h': /* Solaris: supress printing of file name */
229 269 hflag = 1;
230 270 Hflag = 0;
231 271 break;
232 272 /* Solaris: precede every matching with file name */
233 273 case 'H':
234 274 Hflag = 1;
235 275 hflag = 0;
236 276 break;
237 277
238 278 case 'q': /* POSIX: quiet: status only */
239 279 qflag++;
240 280 break;
241 281
242 282 case 'w': /* Solaris: treat pattern as word */
243 283 wflag++;
244 284 break;
245 285
246 286 case 'x': /* POSIX: full line matches */
247 287 xflag++;
248 288 regflags |= REG_ANCHOR;
249 289 break;
250 290
251 291 case 'E': /* POSIX: Extended RE's */
252 292 regflags |= REG_EXTENDED;
253 293 Eflag++;
254 294 break;
↓ open down ↓ |
79 lines elided |
↑ open up ↑ |
255 295
256 296 case 'F': /* POSIX: strings, not RE's */
257 297 Fflag++;
258 298 break;
259 299
260 300 case 'R': /* Solaris: like rflag, but follow symlinks */
261 301 Rflag++;
262 302 rflag++;
263 303 break;
264 304
305 + case 'A': /* print N lines after each match */
306 + conalen = strtoul(optarg, &test, 10);
307 + /* *test will be non-null if optarg is negative */
308 + if (*test != '\0' || conalen >= ULONG_MAX) {
309 + (void) fprintf(stderr, gettext(
310 + "%s: Bad context argument\n"), argv[0]);
311 + exit(2);
312 + }
313 + if (conalen)
314 + conflag |= AFTER;
315 + else
316 + conflag &= ~AFTER;
317 + break;
318 + case 'B': /* print N lines before each match */
319 + conblen = strtoul(optarg, &test, 10);
320 + /* *test will be non-null if optarg is negative */
321 + if (*test != '\0' || conblen >= ULONG_MAX) {
322 + (void) fprintf(stderr, gettext(
323 + "%s: Bad context argument\n"), argv[0]);
324 + exit(2);
325 + }
326 + if (conblen)
327 + conflag |= BEFORE;
328 + else
329 + conflag &= ~BEFORE;
330 + break;
331 + case 'C': /* print N lines around each match */
332 + tval = strtoul(optarg, &test, 10);
333 + /* *test will be non-null if optarg is negative */
334 + if (*test != '\0' || tval >= ULONG_MAX) {
335 + (void) fprintf(stderr, gettext(
336 + "%s: Bad context argument\n"), argv[0]);
337 + exit(2);
338 + }
339 + if (tval) {
340 + if (!(conflag & BEFORE))
341 + conblen = tval;
342 + if (!(conflag & AFTER))
343 + conalen = tval;
344 + conflag = CONTEXT;
345 + }
346 + break;
347 +
265 348 default:
266 349 usage();
267 350 }
268 351 }
269 352 /*
270 353 * If we're invoked as egrep or fgrep we need to do some checks
271 354 */
272 355
273 356 if (egrep || fgrep) {
274 357 /*
275 358 * Use of -E or -F with egrep or fgrep is illegal
276 359 */
277 360 if (Eflag || Fflag)
278 361 usage();
279 362 /*
280 363 * Don't allow use of wflag with egrep / fgrep
281 364 */
282 365 if (wflag)
283 366 usage();
284 367 /*
285 368 * For Solaris the -s flag is equivalent to XCU -q
286 369 */
287 370 if (sflag)
288 371 qflag++;
289 372 /*
290 373 * done with above checks - set the appropriate flags
291 374 */
292 375 if (egrep)
293 376 Eflag++;
294 377 else /* Else fgrep */
295 378 Fflag++;
296 379 }
297 380
298 381 if (wflag && (Eflag || Fflag)) {
299 382 /*
300 383 * -w cannot be specified with grep -F
301 384 */
302 385 usage();
303 386 }
304 387
305 388 /*
306 389 * -E and -F flags are mutually exclusive - check for this
307 390 */
308 391 if (Eflag && Fflag)
309 392 usage();
310 393
311 394 /*
312 395 * -l overrides -H like in GNU grep
313 396 */
314 397 if (lflag)
315 398 Hflag = 0;
316 399
317 400 /*
318 401 * -c, -l and -q flags are mutually exclusive
319 402 * We have -c override -l like in Solaris.
320 403 * -q overrides -l & -c programmatically in grep() function.
321 404 */
322 405 if (cflag && lflag)
323 406 lflag = 0;
324 407
325 408 argv += optind - 1;
326 409 argc -= optind - 1;
327 410
328 411 /*
329 412 * Now handling -e and -f option
330 413 */
331 414 if (pattern_list) {
332 415 for (i = 0; i < n_pattern; i++) {
333 416 addpattern(pattern_list[i]);
334 417 }
335 418 free(pattern_list);
336 419 }
337 420 if (file_list) {
338 421 for (i = 0; i < n_file; i++) {
339 422 addfile(file_list[i]);
340 423 }
341 424 free(file_list);
342 425 }
343 426
344 427 /*
345 428 * No -e or -f? Make sure there is one more arg, use it as the pattern.
346 429 */
347 430 if (patterns == NULL && !fflag) {
348 431 if (argc < 2)
349 432 usage();
350 433 addpattern(argv[1]);
351 434 argc--;
352 435 argv++;
353 436 }
354 437
355 438 /*
356 439 * If -x flag is not specified or -i flag is specified
357 440 * with fgrep in a multibyte locale, need to use
358 441 * the wide character APIs. Otherwise, byte-oriented
359 442 * process will be done.
360 443 */
361 444 use_wchar = Fflag && mblocale && (!xflag || iflag);
362 445
363 446 /*
364 447 * Compile Patterns and also decide if BMG can be used
365 448 */
366 449 fixpatterns();
367 450
368 451 /* Process all files: stdin, or rest of arg list */
369 452 if (argc < 2) {
370 453 matched = grep(0, STDIN_FILENAME);
371 454 } else {
372 455 if (Hflag || (argc > 2 && hflag == 0))
373 456 outfn = 1; /* Print filename on match line */
374 457 for (argv++; *argv != NULL; argv++) {
375 458 process_path(*argv);
376 459 }
377 460 }
378 461 /*
379 462 * Return() here is used instead of exit
380 463 */
381 464
382 465 (void) fflush(stdout);
383 466
384 467 if (errors)
385 468 return (2);
386 469 return (matched ? 0 : 1);
387 470 }
388 471
389 472 static void
390 473 process_path(const char *path)
391 474 {
392 475 struct stat st;
393 476 int walkflags = FTW_CHDIR;
394 477 char *buf = NULL;
395 478
396 479 if (rflag) {
397 480 if (stat(path, &st) != -1 &&
398 481 (st.st_mode & S_IFMT) == S_IFDIR) {
399 482 outfn = 1; /* Print filename */
400 483
401 484 /*
402 485 * Add trailing slash if arg
403 486 * is directory, to resolve symlinks.
404 487 */
405 488 if (path[strlen(path) - 1] != '/') {
406 489 (void) asprintf(&buf, "%s/", path);
407 490 if (buf != NULL)
408 491 path = buf;
409 492 }
410 493
411 494 /*
412 495 * Search through subdirs if path is directory.
413 496 * Don't follow symlinks if Rflag is not set.
414 497 */
415 498 if (!Rflag)
416 499 walkflags |= FTW_PHYS;
417 500
418 501 if (nftw(path, recursive, MAX_DEPTH, walkflags) != 0) {
419 502 if (!sflag)
420 503 (void) fprintf(stderr,
421 504 gettext("%s: can't open \"%s\"\n"),
422 505 cmdname, path);
423 506 errors = 1;
424 507 }
425 508 return;
426 509 }
427 510 }
428 511 process_file(path, 0);
429 512 }
430 513
431 514 /*
432 515 * Read and process all files in directory recursively.
433 516 */
434 517 static int
435 518 recursive(const char *name, const struct stat *statp, int info, struct FTW *ftw)
436 519 {
437 520 /*
438 521 * Process files and follow symlinks if Rflag set.
439 522 */
440 523 if (info != FTW_F) {
441 524 /* Report broken symlinks and unreadable files */
442 525 if (!sflag &&
443 526 (info == FTW_SLN || info == FTW_DNR || info == FTW_NS)) {
444 527 (void) fprintf(stderr,
445 528 gettext("%s: can't open \"%s\"\n"), cmdname, name);
446 529 }
447 530 return (0);
448 531 }
449 532
450 533
451 534 /* Skip devices and pipes if Rflag is not set */
452 535 if (!Rflag && !S_ISREG(statp->st_mode))
453 536 return (0);
454 537 /* Pass offset to relative name from FTW_CHDIR */
455 538 process_file(name, ftw->base);
456 539 return (0);
457 540 }
458 541
459 542 /*
460 543 * Opens file and call grep function.
461 544 */
462 545 static void
463 546 process_file(const char *name, int base)
464 547 {
465 548 int fd;
466 549
467 550 if ((fd = open(name + base, O_RDONLY)) == -1) {
468 551 errors = 1;
469 552 if (!sflag) /* Silent mode */
470 553 (void) fprintf(stderr, gettext(
471 554 "%s: can't open \"%s\"\n"),
472 555 cmdname, name);
473 556 return;
474 557 }
475 558 matched |= grep(fd, name);
476 559 (void) close(fd);
477 560
478 561 if (ferror(stdout)) {
479 562 (void) fprintf(stderr, gettext(
480 563 "%s: error writing to stdout\n"),
481 564 cmdname);
482 565 (void) fflush(stdout);
483 566 exit(2);
484 567 }
485 568
486 569 }
487 570
488 571 /*
489 572 * Add a file of strings to the pattern list.
490 573 */
491 574 static void
492 575 addfile(const char *fn)
493 576 {
494 577 FILE *fp;
495 578 char *inbuf;
496 579 char *bufp;
497 580 size_t bufsiz, buflen, bufused;
498 581
499 582 /*
500 583 * Open the pattern file
501 584 */
502 585 if ((fp = fopen(fn, "r")) == NULL) {
503 586 (void) fprintf(stderr, gettext("%s: can't open \"%s\"\n"),
504 587 cmdname, fn);
505 588 exit(2);
506 589 }
507 590 bufsiz = BUFSIZE;
508 591 if ((inbuf = malloc(bufsiz)) == NULL) {
509 592 (void) fprintf(stderr,
510 593 gettext("%s: out of memory\n"), cmdname);
511 594 exit(2);
512 595 }
513 596 bufp = inbuf;
514 597 bufused = 0;
515 598 /*
516 599 * Read in the file, reallocing as we need more memory
517 600 */
518 601 while (fgets(bufp, bufsiz - bufused, fp) != NULL) {
519 602 buflen = strlen(bufp);
520 603 bufused += buflen;
521 604 if (bufused + 1 == bufsiz && bufp[buflen - 1] != '\n') {
522 605 /*
523 606 * if this line does not fit to the buffer,
524 607 * realloc larger buffer
525 608 */
526 609 bufsiz += BUFSIZE;
527 610 if ((inbuf = realloc(inbuf, bufsiz)) == NULL) {
528 611 (void) fprintf(stderr,
529 612 gettext("%s: out of memory\n"),
530 613 cmdname);
531 614 exit(2);
532 615 }
533 616 bufp = inbuf + bufused;
534 617 continue;
↓ open down ↓ |
260 lines elided |
↑ open up ↑ |
535 618 }
536 619 if (bufp[buflen - 1] == '\n') {
537 620 bufp[--buflen] = '\0';
538 621 }
539 622 addpattern(inbuf);
540 623
541 624 bufp = inbuf;
542 625 bufused = 0;
543 626 }
544 627 free(inbuf);
628 + free(prntbuf);
629 + free(conbuf);
545 630 (void) fclose(fp);
546 631 }
547 632
548 633 /*
549 634 * Add a string to the pattern list.
550 635 */
551 636 static void
552 637 addpattern(char *s)
553 638 {
554 639 PATTERN *pp;
555 640 char *wordbuf;
556 641 char *np;
557 642
558 643 for (; ; ) {
559 644 np = strchr(s, '\n');
560 645 if (np != NULL)
561 646 *np = '\0';
562 647 if ((pp = malloc(sizeof (PATTERN))) == NULL) {
563 648 (void) fprintf(stderr, gettext(
564 649 "%s: out of memory\n"),
565 650 cmdname);
566 651 exit(2);
567 652 }
568 653 if (wflag) {
569 654 /*
570 655 * Solaris wflag support: Add '<' '>' to pattern to
571 656 * select it as a word. Doesn't make sense with -F
572 657 * but we're Libertarian.
573 658 */
574 659 size_t slen, wordlen;
575 660
576 661 slen = strlen(s);
577 662 wordlen = slen + 5; /* '\\' '<' s '\\' '>' '\0' */
578 663 if ((wordbuf = malloc(wordlen)) == NULL) {
579 664 (void) fprintf(stderr,
580 665 gettext("%s: out of memory\n"),
581 666 cmdname);
582 667 exit(2);
583 668 }
584 669 (void) strcpy(wordbuf, "\\<");
585 670 (void) strcpy(wordbuf + 2, s);
586 671 (void) strcpy(wordbuf + 2 + slen, "\\>");
587 672 } else {
588 673 if ((wordbuf = strdup(s)) == NULL) {
589 674 (void) fprintf(stderr,
590 675 gettext("%s: out of memory\n"),
591 676 cmdname);
592 677 exit(2);
593 678 }
594 679 }
595 680 pp->pattern = wordbuf;
596 681 pp->next = patterns;
597 682 patterns = pp;
598 683 if (np == NULL)
599 684 break;
600 685 s = np + 1;
601 686 }
602 687 }
603 688
604 689 /*
605 690 * Fix patterns.
606 691 * Must do after all arguments read, in case later -i option.
607 692 */
608 693 static void
609 694 fixpatterns(void)
610 695 {
611 696 PATTERN *pp;
612 697 int rv, fix_pattern, npatterns;
613 698
614 699 /*
615 700 * As REG_ANCHOR flag is not supported in the current Solaris,
616 701 * need to fix the specified pattern if -x is specified with
617 702 * grep or egrep
618 703 */
619 704 fix_pattern = !Fflag && xflag;
620 705
621 706 for (npatterns = 0, pp = patterns; pp != NULL; pp = pp->next) {
622 707 npatterns++;
623 708 if (fix_pattern) {
624 709 char *cp, *cq;
625 710 size_t plen, nplen;
626 711
627 712 plen = strlen(pp->pattern);
628 713 /* '^' pattern '$' */
629 714 nplen = 1 + plen + 1 + 1;
630 715 if ((cp = malloc(nplen)) == NULL) {
631 716 (void) fprintf(stderr,
632 717 gettext("%s: out of memory\n"),
633 718 cmdname);
634 719 exit(2);
635 720 }
636 721 cq = cp;
637 722 *cq++ = '^';
638 723 cq = strcpy(cq, pp->pattern) + plen;
639 724 *cq++ = '$';
640 725 *cq = '\0';
641 726 free(pp->pattern);
642 727 pp->pattern = cp;
643 728 }
644 729
645 730 if (Fflag) {
646 731 if (use_wchar) {
647 732 /*
648 733 * Fflag && mblocale && iflag
649 734 * Fflag && mblocale && !xflag
650 735 */
651 736 size_t n;
652 737 n = strlen(pp->pattern) + 1;
653 738 if ((pp->wpattern =
654 739 malloc(sizeof (wchar_t) * n)) == NULL) {
655 740 (void) fprintf(stderr,
656 741 gettext("%s: out of memory\n"),
657 742 cmdname);
658 743 exit(2);
659 744 }
660 745 if (mbstowcs(pp->wpattern, pp->pattern, n) ==
661 746 (size_t)-1) {
662 747 (void) fprintf(stderr,
663 748 gettext("%s: failed to convert "
664 749 "\"%s\" to wide-characters\n"),
665 750 cmdname, pp->pattern);
666 751 exit(2);
667 752 }
668 753 if (iflag) {
669 754 wchar_t *wp;
670 755 for (wp = pp->wpattern; *wp != L'\0';
671 756 wp++) {
672 757 *wp = towlower((wint_t)*wp);
673 758 }
674 759 }
675 760 free(pp->pattern);
676 761 } else {
677 762 /*
678 763 * Fflag && mblocale && !iflag
679 764 * Fflag && !mblocale && iflag
680 765 * Fflag && !mblocale && !iflag
681 766 */
682 767 if (iflag) {
683 768 unsigned char *cp;
684 769 for (cp = (unsigned char *)pp->pattern;
685 770 *cp != '\0'; cp++) {
686 771 *cp = tolower(*cp);
687 772 }
688 773 }
689 774 }
690 775 /*
691 776 * fgrep: No regular expressions.
692 777 */
693 778 continue;
694 779 }
695 780
696 781 /*
697 782 * For non-fgrep, compile the regular expression,
698 783 * give an informative error message, and exit if
699 784 * it didn't compile.
700 785 */
701 786 if ((rv = regcomp(&pp->re, pp->pattern, regflags)) != 0) {
702 787 (void) regerror(rv, &pp->re, errstr, sizeof (errstr));
703 788 (void) fprintf(stderr,
704 789 gettext("%s: RE error in %s: %s\n"),
705 790 cmdname, pp->pattern, errstr);
706 791 exit(2);
707 792 }
708 793 free(pp->pattern);
709 794 }
710 795
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
711 796 /*
712 797 * Decide if we are able to run the Boyer-Moore-Gosper algorithm.
713 798 * Use the Boyer-Moore-Gosper algorithm if:
714 799 * - fgrep (Fflag)
715 800 * - singlebyte locale (!mblocale)
716 801 * - no ignoring case (!iflag)
717 802 * - no printing line numbers (!nflag)
718 803 * - no negating the output (nvflag)
719 804 * - only one pattern (npatterns == 1)
720 805 * - non zero length pattern (strlen(patterns->pattern) != 0)
806 + * - no context required (!conflag)
721 807 *
722 808 * It's guaranteed patterns->pattern is still alive
723 809 * when Fflag && !mblocale.
724 810 */
725 811 use_bmg = Fflag && !mblocale && !iflag && !nflag && nvflag &&
726 - (npatterns == 1) && (strlen(patterns->pattern) != 0);
812 + (npatterns == 1) && (strlen(patterns->pattern) != 0) && !conflag;
727 813 }
728 814
729 815 /*
730 816 * Search a newline from the beginning of the string
731 817 */
732 818 static char *
733 819 find_nl(const char *ptr, size_t len)
734 820 {
735 821 while (len-- != 0) {
736 822 if (*ptr++ == '\n') {
737 823 return ((char *)--ptr);
738 824 }
739 825 }
740 826 return (NULL);
741 827 }
742 828
743 829 /*
744 830 * Search a newline from the end of the string
745 831 */
746 832 static char *
747 833 rfind_nl(const char *ptr, size_t len)
748 834 {
749 835 const char *uptr = ptr + len;
750 836 while (len--) {
751 837 if (*--uptr == '\n') {
752 838 return ((char *)uptr);
753 839 }
754 840 }
755 841 return (NULL);
756 842 }
757 843
758 844 /*
759 845 * Duplicate the specified string converting each character
760 846 * into a lower case.
761 847 */
762 848 static char *
763 849 istrdup(const char *s1)
764 850 {
765 851 static size_t ibuflen = 0;
766 852 static char *ibuf = NULL;
767 853 size_t slen;
768 854 char *p;
769 855
770 856 slen = strlen(s1);
771 857 if (slen >= ibuflen) {
772 858 /* ibuf does not fit to s1 */
773 859 ibuflen = slen + 1;
774 860 ibuf = realloc(ibuf, ibuflen);
775 861 if (ibuf == NULL) {
776 862 (void) fprintf(stderr,
777 863 gettext("%s: out of memory\n"), cmdname);
778 864 exit(2);
779 865 }
780 866 }
781 867 p = ibuf;
782 868 do {
783 869 *p++ = tolower(*s1);
784 870 } while (*s1++ != '\0');
785 871 return (ibuf);
786 872 }
787 873
788 874 /*
789 875 * Do grep on a single file.
790 876 * Return true in any lines matched.
791 877 *
792 878 * We have two strategies:
793 879 * The fast one is used when we have a single pattern with
794 880 * a string known to occur in the pattern. We can then
795 881 * do a BMG match on the whole buffer.
796 882 * This is an order of magnitude faster.
↓ open down ↓ |
60 lines elided |
↑ open up ↑ |
797 883 * Otherwise we split the buffer into lines,
798 884 * and check for a match on each line.
799 885 */
800 886 static int
801 887 grep(int fd, const char *fn)
802 888 {
803 889 PATTERN *pp;
804 890 off_t data_len; /* length of the data chunk */
805 891 off_t line_len; /* length of the current line */
806 892 off_t line_offset; /* current line's offset from the beginning */
807 - long long lineno;
893 + off_t blkoffset; /* line_offset but context-compatible */
894 + long long lineno, linenum;
808 895 long long matches = 0; /* Number of matching lines */
896 + long long conacnt = 0, conbcnt = 0; /* context line count */
809 897 int newlinep; /* 0 if the last line of file has no newline */
810 - char *ptr, *ptrend;
898 + char *ptr, *ptrend, *prntptr, *prntptrend;
899 + char *nextptr = NULL, *nextend = NULL;
900 + char *conptr = NULL, *conptrend = NULL;
901 + char *matchptr = NULL;
902 + int conaprnt = 0, conbprnt = 0, lastmatch = 0;
903 + int nearmatch = conmatches ? 1 : 0; /* w/in N+1 of last match */
904 + size_t prntlen;
811 905
812 -
813 906 if (patterns == NULL)
814 907 return (0); /* no patterns to match -- just return */
815 908
816 909 pp = patterns;
817 910
818 911 if (use_bmg) {
819 912 bmgcomp(pp->pattern, strlen(pp->pattern));
820 913 }
821 914
822 915 if (use_wchar && outline == NULL) {
823 916 outbuflen = BUFSIZE + 1;
824 917 outline = malloc(sizeof (wchar_t) * outbuflen);
825 918 if (outline == NULL) {
826 919 (void) fprintf(stderr, gettext("%s: out of memory\n"),
827 920 cmdname);
828 921 exit(2);
829 922 }
830 923 }
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
831 924
832 925 if (prntbuf == NULL) {
833 926 prntbuflen = BUFSIZE;
834 927 if ((prntbuf = malloc(prntbuflen + 1)) == NULL) {
835 928 (void) fprintf(stderr, gettext("%s: out of memory\n"),
836 929 cmdname);
837 930 exit(2);
838 931 }
839 932 }
840 933
841 - line_offset = 0;
934 + if (conflag && (conbuf == NULL)) {
935 + conbuflen = BUFSIZE;
936 + if ((conbuf = malloc(BUFSIZE+1)) == NULL) {
937 + (void) fprintf(stderr, gettext("%s: out of memory\n"),
938 + cmdname);
939 + exit(2);
940 + }
941 + }
942 +
943 + blkoffset = line_offset = 0;
842 944 lineno = 0;
945 + linenum = 1;
843 946 newlinep = 1;
844 947 data_len = 0;
845 948 for (; ; ) {
846 949 long count;
847 950 off_t offset = 0;
951 + int eof = 0, rv = REG_NOMATCH;
952 + char separate;
848 953
849 954 if (data_len == 0) {
850 955 /*
851 956 * If no data in the buffer, reset ptr
852 957 */
853 958 ptr = prntbuf;
959 + if (conptr == NULL)
960 + conptrend = conptr = conbuf;
854 961 }
855 962 if (ptr == prntbuf) {
856 963 /*
857 964 * The current data chunk starts from prntbuf.
858 965 * This means either the buffer has no data
859 966 * or the buffer has no newline.
860 967 * So, read more data from input.
861 968 */
862 969 count = read(fd, ptr + data_len, prntbuflen - data_len);
863 970 if (count < 0) {
864 971 /* read error */
865 972 if (cflag) {
866 973 if (outfn && !rflag) {
867 974 (void) fprintf(stdout,
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
868 975 "%s:", fn);
869 976 }
870 977 if (!qflag && !rflag) {
871 978 (void) fprintf(stdout, "%lld\n",
872 979 matches);
873 980 }
874 981 }
875 982 return (0);
876 983 } else if (count == 0) {
877 984 /* no new data */
985 + eof = 1;
986 +
987 + /* we never want to match EOF */
988 + pp = (PATTERN *) !nvflag;
989 +
878 990 if (data_len == 0) {
879 991 /* end of file already reached */
880 - break;
992 + if (conflag) {
993 + *conptrend = '\n';
994 + goto L_next_line;
995 + } else {
996 + goto out;
997 + }
881 998 }
882 999 /* last line of file has no newline */
883 1000 ptrend = ptr + data_len;
884 1001 newlinep = 0;
885 1002 goto L_start_process;
886 1003 }
887 1004 offset = data_len;
888 1005 data_len += count;
889 1006 }
890 1007
891 1008 /*
892 1009 * Look for newline in the chunk
893 1010 * between ptr + offset and ptr + data_len - offset.
894 1011 */
895 1012 ptrend = find_nl(ptr + offset, data_len - offset);
896 1013 if (ptrend == NULL) {
897 1014 /* no newline found in this chunk */
898 1015 if (ptr > prntbuf) {
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
899 1016 /*
900 1017 * Move remaining data to the beginning
901 1018 * of the buffer.
902 1019 * Remaining data lie from ptr for
903 1020 * data_len bytes.
904 1021 */
905 1022 (void) memmove(prntbuf, ptr, data_len);
906 1023 }
907 1024 if (data_len == prntbuflen) {
908 1025 /*
909 - * No enough room in the buffer
1026 + * Not enough room in the buffer
910 1027 */
911 1028 prntbuflen += BUFSIZE;
912 1029 prntbuf = realloc(prntbuf, prntbuflen + 1);
913 1030 if (prntbuf == NULL) {
914 1031 (void) fprintf(stderr,
915 1032 gettext("%s: out of memory\n"),
916 1033 cmdname);
917 1034 exit(2);
918 1035 }
919 1036 }
920 1037 ptr = prntbuf;
921 1038 /* read the next input */
922 1039 continue;
923 1040 }
924 1041 L_start_process:
925 1042
926 1043 /*
927 1044 * Beginning of the chunk: ptr
928 1045 * End of the chunk: ptr + data_len
929 1046 * Beginning of the line: ptr
930 1047 * End of the line: ptrend
931 1048 */
932 1049
933 1050 if (use_bmg) {
934 1051 /*
935 1052 * Use Boyer-Moore-Gosper algorithm to find out if
936 1053 * this chunk (not this line) contains the specified
937 1054 * pattern. If not, restart from the last line
938 1055 * of this chunk.
939 1056 */
940 1057 char *bline;
941 1058 bline = bmgexec(ptr, ptr + data_len);
942 1059 if (bline == NULL) {
943 1060 /*
944 1061 * No pattern found in this chunk.
945 1062 * Need to find the last line
946 1063 * in this chunk.
947 1064 */
948 1065 ptrend = rfind_nl(ptr, data_len);
949 1066
950 1067 /*
951 1068 * When this chunk does not contain newline,
952 1069 * ptrend becomes NULL, which should happen
953 1070 * when the last line of file does not end
954 1071 * with a newline. At such a point,
955 1072 * newlinep should have been set to 0.
956 1073 * Therefore, just after jumping to
957 1074 * L_skip_line, the main for-loop quits,
958 1075 * and the line_len value won't be
959 1076 * used.
960 1077 */
961 1078 line_len = ptrend - ptr;
962 1079 goto L_skip_line;
963 1080 }
964 1081 if (bline > ptrend) {
965 1082 /*
966 1083 * Pattern found not in the first line
967 1084 * of this chunk.
968 1085 * Discard the first line.
969 1086 */
970 1087 line_len = ptrend - ptr;
971 1088 goto L_skip_line;
972 1089 }
973 1090 /*
974 1091 * Pattern found in the first line of this chunk.
975 1092 * Using this result.
976 1093 */
977 1094 *ptrend = '\0';
978 1095 line_len = ptrend - ptr;
979 1096
980 1097 /*
981 1098 * before jumping to L_next_line,
982 1099 * need to handle xflag if specified
983 1100 */
984 1101 if (xflag && (line_len != bmglen ||
985 1102 strcmp(bmgpat, ptr) != 0)) {
986 1103 /* didn't match */
987 1104 pp = NULL;
988 1105 } else {
989 1106 pp = patterns; /* to make it happen */
990 1107 }
991 1108 goto L_next_line;
992 1109 }
993 1110 lineno++;
994 1111 /*
995 1112 * Line starts from ptr and ends at ptrend.
996 1113 * line_len will be the length of the line.
997 1114 */
998 1115 *ptrend = '\0';
999 1116 line_len = ptrend - ptr;
1000 1117
1001 1118 /*
1002 1119 * From now, the process will be performed based
1003 1120 * on the line from ptr to ptrend.
1004 1121 */
1005 1122 if (use_wchar) {
1006 1123 size_t len;
1007 1124
1008 1125 if (line_len >= outbuflen) {
1009 1126 outbuflen = line_len + 1;
1010 1127 outline = realloc(outline,
1011 1128 sizeof (wchar_t) * outbuflen);
1012 1129 if (outline == NULL) {
1013 1130 (void) fprintf(stderr,
1014 1131 gettext("%s: out of memory\n"),
1015 1132 cmdname);
1016 1133 exit(2);
1017 1134 }
1018 1135 }
1019 1136
1020 1137 len = mbstowcs(outline, ptr, line_len);
1021 1138 if (len == (size_t)-1) {
1022 1139 (void) fprintf(stderr, gettext(
1023 1140 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1024 1141 cmdname, fn, lineno);
1025 1142 /* never match a line with invalid sequence */
1026 1143 goto L_skip_line;
1027 1144 }
1028 1145 outline[len] = L'\0';
1029 1146
1030 1147 if (iflag) {
1031 1148 wchar_t *cp;
1032 1149 for (cp = outline; *cp != '\0'; cp++) {
↓ open down ↓ |
113 lines elided |
↑ open up ↑ |
1033 1150 *cp = towlower((wint_t)*cp);
1034 1151 }
1035 1152 }
1036 1153
1037 1154 if (xflag) {
1038 1155 for (pp = patterns; pp; pp = pp->next) {
1039 1156 if (outline[0] == pp->wpattern[0] &&
1040 1157 wcscmp(outline,
1041 1158 pp->wpattern) == 0) {
1042 1159 /* matched */
1160 + rv = REG_OK;
1043 1161 break;
1044 1162 }
1045 1163 }
1046 1164 } else {
1047 1165 for (pp = patterns; pp; pp = pp->next) {
1048 1166 if (wcswcs(outline, pp->wpattern)
1049 1167 != NULL) {
1050 1168 /* matched */
1169 + rv = REG_OK;
1051 1170 break;
1052 1171 }
1053 1172 }
1054 1173 }
1055 1174 } else if (Fflag) {
1056 1175 /* fgrep in byte-oriented handling */
1057 1176 char *fptr;
1058 1177 if (iflag) {
1059 1178 fptr = istrdup(ptr);
1060 1179 } else {
1061 1180 fptr = ptr;
1062 1181 }
1063 1182 if (xflag) {
1064 1183 /* fgrep -x */
1065 1184 for (pp = patterns; pp; pp = pp->next) {
1066 1185 if (fptr[0] == pp->pattern[0] &&
1067 1186 strcmp(fptr, pp->pattern) == 0) {
1068 1187 /* matched */
1188 + rv = REG_OK;
1069 1189 break;
1070 1190 }
1071 1191 }
1072 1192 } else {
1073 1193 for (pp = patterns; pp; pp = pp->next) {
1074 1194 if (strstr(fptr, pp->pattern) != NULL) {
1075 1195 /* matched */
1196 + rv = REG_OK;
1076 1197 break;
1077 1198 }
1078 1199 }
1079 1200 }
1080 1201 } else {
1081 1202 /* grep or egrep */
1082 1203 for (pp = patterns; pp; pp = pp->next) {
1083 - int rv;
1084 -
1085 1204 rv = regexec(&pp->re, ptr, 0, NULL, 0);
1086 1205 if (rv == REG_OK) {
1087 1206 /* matched */
1088 1207 break;
1089 1208 }
1090 1209
1091 1210 switch (rv) {
1092 1211 case REG_NOMATCH:
1093 1212 break;
1094 1213 case REG_ECHAR:
1095 1214 (void) fprintf(stderr, gettext(
1096 1215 "%s: input file \"%s\": line %lld: invalid multibyte character\n"),
1097 1216 cmdname, fn, lineno);
1098 1217 break;
1099 1218 default:
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
1100 1219 (void) regerror(rv, &pp->re, errstr,
1101 1220 sizeof (errstr));
1102 1221 (void) fprintf(stderr, gettext(
1103 1222 "%s: input file \"%s\": line %lld: %s\n"),
1104 1223 cmdname, fn, lineno, errstr);
1105 1224 exit(2);
1106 1225 }
1107 1226 }
1108 1227 }
1109 1228
1229 + /*
1230 + * Context is set up as follows:
1231 + * For a 'Before' context, we maintain a set of pointers
1232 + * containing 'N' lines of context. If the current number of
1233 + * lines contained is greater than N, and N isn't a match, the
1234 + * start pointer is moved forward to the next newline.
1235 + *
1236 + * If we ever find a match, we print out immediately.
1237 + * 'nearmatch' tells us if we're within N+1 lines of the last
1238 + * match ; if we are, and we find another match, we don't
1239 + * separate the matches. 'nearmatch' becomes false when
1240 + * a line gets rotated out of the context.
1241 + *
1242 + * For an 'After' context, we simply wait until we've found a
1243 + * match, then create a context N+1 lines big. If we don't find
1244 + * a match within the context, we print out the current context.
1245 + * Otherwise, we save a reference to the new matching line,
1246 + * print out the other context, and reset our context pointers
1247 + * to the new matching line.
1248 + *
1249 + * 'nearmatch' becomes false when we find a non-matching line
1250 + * that isn't a part of any context.
1251 + *
1252 + * A full-context is implemented as a combination of the
1253 + * 'Before' and 'After' context logic. Before we find a match,
1254 + * we follow the Before logic. When we find a match, we
1255 + * follow the After logic. 'nearmatch' is handled by the Before
1256 + * logic.
1257 + */
1258 +
1259 + if (!conflag)
1260 + goto L_next_line;
1261 +
1262 + if (line_len + (conptrend - conbuf) > conbuflen) {
1263 + char *oldconbuf = conbuf;
1264 + char *oldconptr = conptr;
1265 + long tmp = matchptr - conptr;
1266 +
1267 + conbuflen += BUFSIZE;
1268 + conbuf = realloc(conbuf, conbuflen + 1);
1269 + if (conbuf == NULL) {
1270 + (void) fprintf(stderr,
1271 + gettext("%s: out of memory\n"),
1272 + cmdname);
1273 + exit(2);
1274 + }
1275 +
1276 + conptr = conbuf + (conptr - oldconbuf);
1277 + conptrend = conptr + (conptrend - oldconptr);
1278 + if (matchptr)
1279 + matchptr = conptr + tmp;
1280 + }
1281 + (void) memcpy((conptrend > conptr) ?
1282 + conptrend + 1 : conptrend, ptr, line_len);
1283 + conptrend += line_len + (conptrend > conptr);
1284 + *conptrend = '\n';
1285 +
1286 + if (!nvflag == rv) {
1287 + /* matched */
1288 + if (lastmatch) {
1289 + if (conflag & AFTER) {
1290 + conaprnt = 1;
1291 + nextend = conptrend;
1292 + conptrend = conptr + lastmatch;
1293 + nextptr = conptrend + 1;
1294 + *nextend = '\n';
1295 + }
1296 + } else {
1297 + if (conflag == AFTER) {
1298 + conptr = conptrend - (line_len);
1299 + linenum = lineno;
1300 + blkoffset = line_offset;
1301 + }
1302 + blkoffset = line_offset -
1303 + (conptrend - conptr - line_len);
1304 + }
1305 +
1306 + if (conflag == BEFORE)
1307 + conbprnt = 1;
1308 +
1309 + lastmatch = conptrend - conptr;
1310 + goto L_next_line;
1311 + }
1312 +
1313 + if (!lastmatch) {
1314 + if (conflag & BEFORE) {
1315 + if (conbcnt >= conblen) {
1316 + char *tmp = conptr;
1317 + conptr = find_nl(conptr,
1318 + conptrend - conptr) + 1;
1319 + if (bflag)
1320 + blkoffset += conptr - tmp;
1321 + linenum++;
1322 + nearmatch = 1;
1323 + } else {
1324 + conbcnt++;
1325 + }
1326 + }
1327 + if (conflag == AFTER)
1328 + nearmatch = 1;
1329 + } else {
1330 + if (++conacnt >= conalen && !conaprnt && conalen)
1331 + conaprnt = 1;
1332 + else
1333 + lastmatch = conptrend - conptr;
1334 + }
1335 +
1110 1336 L_next_line:
1111 1337 /*
1112 1338 * Here, if pp points to non-NULL, something has been matched
1113 1339 * to the pattern.
1114 1340 */
1115 1341 if (nvflag == (pp != NULL)) {
1116 1342 matches++;
1343 + if (!nextend)
1344 + matchptr = conflag ? conptrend : ptrend;
1345 + }
1346 +
1347 + /*
1348 + * Set up some print context so that we can treat
1349 + * single-line matches as a zero-N context.
1350 + * Apply CLI flags to each line of the context.
1351 + *
1352 + * For context, we only print if we both have a match and are
1353 + * either at the end of the data stream, or we've previously
1354 + * declared that we want to print for a particular context.
1355 + */
1356 + if (lastmatch && (eof || conaprnt || conbprnt)) {
1357 +
1117 1358 /*
1359 + * We'd normally do this earlier, but we had to
1360 + * escape early because we reached the end of the data.
1361 + */
1362 + if (eof && nextptr)
1363 + conptrend = nextend;
1364 +
1365 + prntlen = conptrend - conptr + 1;
1366 + prntptrend = prntptr = conptr;
1367 + if (conmatches++ && nearmatch && !cflag)
1368 + (void) fwrite("--\n", 1, 3, stdout);
1369 + } else if (!conflag && nvflag == (pp != NULL)) {
1370 + *ptrend = '\n';
1371 + prntlen = line_len + 1;
1372 + prntptrend = prntptr = ptr;
1373 + linenum = lineno;
1374 + blkoffset = line_offset;
1375 + } else if (eof) {
1376 + /* No match and no more data */
1377 + goto out;
1378 + } else {
1379 + /* No match, or we're not done building context */
1380 + goto L_skip_line;
1381 + }
1382 +
1383 + while ((prntptrend = find_nl(prntptrend+1, prntlen)) != NULL) {
1384 +
1385 + /*
1386 + * GNU grep uses '-' for context lines and ':' for
1387 + * matching lines, so replicate that here.
1388 + */
1389 + if (prntptrend == matchptr) {
1390 + if (eof && nextptr) {
1391 + matchptr = nextend;
1392 + nextptr = NULL;
1393 + } else {
1394 + matchptr = NULL;
1395 + }
1396 + separate = ':';
1397 + } else {
1398 + separate = '-';
1399 + }
1400 +
1401 + /*
1118 1402 * Handle q, l, and c flags.
1119 1403 */
1120 1404 if (qflag) {
1121 1405 /* no need to continue */
1122 1406 /*
1123 1407 * End of this line is ptrend.
1124 1408 * We have read up to ptr + data_len.
1125 1409 */
1126 1410 off_t pos;
1127 1411 pos = ptr + data_len - (ptrend + 1);
1128 1412 (void) lseek(fd, -pos, SEEK_CUR);
1129 1413 exit(0);
1130 1414 }
1131 1415 if (lflag) {
1132 1416 (void) printf("%s\n", fn);
1133 - break;
1417 + goto out;
1134 1418 }
1135 1419 if (!cflag) {
1136 1420 if (Hflag || outfn) {
1137 - (void) printf("%s:", fn);
1421 + (void) printf("%s%c", fn, separate);
1138 1422 }
1139 1423 if (bflag) {
1140 - (void) printf("%lld:", (offset_t)
1141 - (line_offset / BSIZE));
1424 + (void) printf("%lld%c", (offset_t)
1425 + (blkoffset / BSIZE), separate);
1142 1426 }
1143 1427 if (nflag) {
1144 - (void) printf("%lld:", lineno);
1428 + (void) printf("%lld%c", linenum,
1429 + separate);
1145 1430 }
1146 - *ptrend = '\n';
1147 - (void) fwrite(ptr, 1, line_len + 1, stdout);
1431 + (void) fwrite(prntptr, 1,
1432 + prntptrend - prntptr + 1, stdout);
1148 1433 }
1149 1434 if (ferror(stdout)) {
1150 1435 return (0);
1151 1436 }
1437 + linenum++;
1438 + prntlen -= prntptrend - prntptr + 1;
1439 + blkoffset += prntptrend - prntptr + 1;
1440 + prntptr = prntptrend + 1;
1152 1441 }
1442 +
1443 + if (eof)
1444 + goto out;
1445 +
1446 + /*
1447 + * Update context buffer and variables post-print
1448 + */
1449 + if (conflag) {
1450 + conptr = conbuf;
1451 + conaprnt = conbprnt = 0;
1452 + nearmatch = 0;
1453 + conacnt = conbcnt = 0;
1454 +
1455 + if (nextptr) {
1456 + (void) memmove(conbuf, nextptr,
1457 + nextend - nextptr + 1);
1458 + blkoffset += nextptr - conptrend - 1;
1459 + conptrend = conptr + (nextend - nextptr);
1460 + matchptr = conptrend;
1461 + linenum = lineno;
1462 + lastmatch = conptrend - conptr;
1463 + } else {
1464 + conptrend = conptr;
1465 + conacnt = 0;
1466 + lastmatch = 0;
1467 + }
1468 + nextptr = nextend = NULL;
1469 + }
1470 +
1153 1471 L_skip_line:
1154 1472 if (!newlinep)
1155 1473 break;
1156 1474
1157 1475 data_len -= line_len + 1;
1158 1476 line_offset += line_len + 1;
1159 1477 ptr = ptrend + 1;
1160 1478 }
1161 1479
1480 +out:
1162 1481 if (cflag) {
1163 1482 if (Hflag || outfn) {
1164 1483 (void) printf("%s:", fn);
1165 1484 }
1166 1485 if (!qflag) {
1167 1486 (void) printf("%lld\n", matches);
1168 1487 }
1169 1488 }
1170 1489 return (matches != 0);
1171 1490 }
1172 1491
1173 1492 /*
1174 1493 * usage message for grep
1175 1494 */
1176 1495 static void
1177 1496 usage(void)
1178 1497 {
1179 1498 if (egrep || fgrep) {
1180 1499 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1181 1500 (void) fprintf(stderr,
1182 - gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1183 - "pattern_list [file ...]\n"));
1501 + gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1502 + "[-bhHinsvx] pattern_list [file ...]\n"));
1184 1503
1185 1504 (void) fprintf(stderr, "\t%s", cmdname);
1186 1505 (void) fprintf(stderr,
1187 - gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1188 - "[-e pattern_list]... "
1506 + gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1507 + "[-bhHinsvx] [-e pattern_list]... "
1189 1508 "[-f pattern_file]... [file...]\n"));
1190 1509 } else {
1191 1510 (void) fprintf(stderr, gettext("Usage:\t%s"), cmdname);
1192 1511 (void) fprintf(stderr,
1193 - gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvwx] "
1194 - "pattern_list [file ...]\n"));
1512 + gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1513 + "[-bhHinsvx] pattern_list [file ...]\n"));
1195 1514
1196 1515 (void) fprintf(stderr, "\t%s", cmdname);
1197 1516 (void) fprintf(stderr,
1198 - gettext(" [-c|-l|-q] [-r|-R] [-bhHinsvwx] "
1199 - "[-e pattern_list]... "
1517 + gettext(" [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1518 + "[-bhHinsvx] [-e pattern_list]... "
1200 1519 "[-f pattern_file]... [file...]\n"));
1201 1520
1202 1521 (void) fprintf(stderr, "\t%s", cmdname);
1203 1522 (void) fprintf(stderr,
1204 - gettext(" -E [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1205 - "pattern_list [file ...]\n"));
1523 + gettext(" -E [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1524 + "[-bhHinsvx] pattern_list [file ...]\n"));
1206 1525
1207 1526 (void) fprintf(stderr, "\t%s", cmdname);
1208 1527 (void) fprintf(stderr,
1209 - gettext(" -E [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1210 - "[-e pattern_list]... "
1528 + gettext(" -E [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1529 + "[-bhHinsvx] [-e pattern_list]... "
1211 1530 "[-f pattern_file]... [file...]\n"));
1212 1531
1213 1532 (void) fprintf(stderr, "\t%s", cmdname);
1214 1533 (void) fprintf(stderr,
1215 - gettext(" -F [-c|-l|-q] [-r|-R] [-bhHinsvx] "
1216 - "pattern_list [file ...]\n"));
1534 + gettext(" -F [-c|-l|-q] [-r|-R] [-A #|-B #|-C #|-#] "
1535 + "[-bhHinsvx] pattern_list [file ...]\n"));
1217 1536
1218 1537 (void) fprintf(stderr, "\t%s", cmdname);
1219 1538 (void) fprintf(stderr,
1220 - gettext(" -F [-c|-l|-q] [-bhHinsvx] [-e pattern_list]... "
1539 + gettext(" -F [-c|-l|-q] [-A #|-B #|-C #|-#] "
1540 + "[-bhHinsvx] [-e pattern_list]... "
1221 1541 "[-f pattern_file]... [file...]\n"));
1222 1542 }
1223 1543 exit(2);
1224 1544 /* NOTREACHED */
1225 1545 }
1226 1546
1227 1547 /*
1228 1548 * Compile literal pattern into BMG tables
1229 1549 */
1230 1550 static void
1231 1551 bmgcomp(char *pat, int len)
1232 1552 {
1233 1553 int i;
1234 1554 int tlen;
1235 1555 unsigned char *uc = (unsigned char *)pat;
1236 1556
1237 1557 bmglen = len;
1238 1558 bmgpat = pat;
1239 1559
1240 1560 for (i = 0; i < M_CSETSIZE; i++) {
1241 1561 bmgtab[i] = len;
1242 1562 }
1243 1563
1244 1564 len--;
1245 1565 for (tlen = len, i = 0; i <= len; i++, tlen--) {
1246 1566 bmgtab[*uc++] = tlen;
1247 1567 }
1248 1568 }
1249 1569
1250 1570 /*
1251 1571 * BMG search.
1252 1572 */
1253 1573 static char *
1254 1574 bmgexec(char *str, char *end)
1255 1575 {
1256 1576 int t;
1257 1577 char *k, *s, *p;
1258 1578
1259 1579 k = str + bmglen - 1;
1260 1580 if (bmglen == 1) {
1261 1581 return (memchr(str, bmgpat[0], end - str));
1262 1582 }
1263 1583 for (; ; ) {
1264 1584 /* inner loop, should be most optimized */
1265 1585 while (k < end && (t = bmgtab[(unsigned char)*k]) != 0) {
1266 1586 k += t;
1267 1587 }
1268 1588 if (k >= end) {
1269 1589 return (NULL);
1270 1590 }
1271 1591 for (s = k, p = bmgpat + bmglen - 1; *--s == *--p; ) {
1272 1592 if (p == bmgpat) {
1273 1593 return (s);
1274 1594 }
1275 1595 }
1276 1596 k++;
1277 1597 }
1278 1598 /* NOTREACHED */
1279 1599 }
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX