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