1 /* fgrep.c - grep program built around matcher.
2 Copyright 1989 Free Software Foundation
3 Written August 1989 by Mike Haertel.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 1, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 The author may be reached (Email) at the address mike@ai.mit.edu,
20 or (US mail) as Mike Haertel c/o Free Software Foundation. */
31 #define NCHAR (UCHAR_MAX + 1)
33 /* For error messages. */
34 static const char *prog
;
35 static int error_seen
;
37 /* Flags controlling the style of output. */
38 static int out_silent
; /* Suppress all normal output. */
39 static int out_invert
; /* Print nonmatching stuff. */
40 static int out_file
; /* Print filenames. */
41 static int out_line
; /* Print line numbers. */
42 static int out_byte
; /* Print byte offsets. */
43 static int out_before
; /* Lines of leading context. */
44 static int out_after
; /* Lines of trailing context. */
46 /* Print MESG and possibly the error string for ERRNUM. Remember
47 that something awful happened. */
49 DEFUN(error
, (mesg
, errnum
), const char *mesg AND
int errnum
)
52 fprintf(stderr
, "%s: %s: %s\n", prog
, mesg
, strerror(errnum
));
54 fprintf(stderr
, "%s: %s\n", prog
, mesg
);
58 /* Like error(), but die horribly after printing. */
60 DEFUN(fatal
, (mesg
, errnum
), const char *mesg AND
int errnum
)
66 /* Interface to handle errors and fix library lossage. */
68 DEFUN(xmalloc
, (size
), size_t size
)
72 result
= malloc(size
);
74 fatal("memory exhausted", 0);
78 /* Interface to handle errors and fix some library lossage. */
80 DEFUN(xrealloc
, (ptr
, size
), PTR ptr AND
size_t size
)
85 result
= realloc(ptr
, size
);
87 result
= malloc(size
);
89 fatal("memory exhausted", 0);
93 /* Compiled search pattern. */
96 /* Flags controlling how pattern matching is performed. */
97 static int match_fold
; /* Fold all letters to one case. */
98 static int match_words
; /* Match only whole words. */
99 static int match_lines
; /* Match only whole lines. */
102 DEFUN(compile
, (pattern
, size
), const char *pattern AND
size_t size
)
104 const char *beg
, *lim
, *err
;
105 static char trans
[NCHAR
];
109 for (i
= 0; i
< NCHAR
; ++i
)
110 trans
[i
] = TOLOWER(i
);
112 if (!(kwset
= kwsalloc(match_fold
? trans
: (const char *) NULL
)))
113 fatal("memory exhausted", 0);
118 for (lim
= beg
; lim
< pattern
+ size
&& *lim
!= '\n'; ++lim
)
120 if (err
= kwsincr(kwset
, beg
, lim
- beg
))
122 if (lim
< pattern
+ size
)
126 while (beg
< pattern
+ size
);
128 if (err
= kwsprep(kwset
))
133 DEFUN(execute
, (buf
, size
), char *buf AND
size_t size
)
135 register char *beg
, *try;
137 struct kwsmatch kwsmatch
;
140 for (;beg
<= buf
+ size
; ++beg
)
142 if (!(beg
= kwsexec(kwset
, beg
, buf
+ size
- beg
, &kwsmatch
)))
144 len
= kwsmatch
.size
[0];
147 if (beg
> buf
&& beg
[-1] != '\n')
149 if (beg
+ len
< buf
+ size
&& *(beg
+ len
) != '\n')
153 else if (match_words
)
154 for (try = beg
; len
&& try;)
156 if (try > buf
&& (ISALNUM((unsigned char) try[-1])
157 || !ISALNUM((unsigned char) *try)))
159 if (try + len
< buf
+ size
160 && (ISALNUM((unsigned char) *(try + len
))
161 || !ISALNUM((unsigned char) (try + len
)[-1])))
166 try = kwsexec(kwset
, beg
, len
, &kwsmatch
);
169 len
= kwsmatch
.size
[0];
178 /* Hairy buffering mechanism to efficiently support all the options. */
179 static char *bufbeg
; /* Beginning of user-visible portion. */
180 static char *buflim
; /* Limit of user-visible portion. */
181 static char *buf
; /* Pointer to base of buffer. */
182 static size_t bufalloc
; /* Allocated size of buffer. */
183 static size_t bufcc
; /* Count of characters in buffer. */
184 static unsigned long int buftotalcc
;
185 /* Total character count since reset. */
186 static char *buflast
; /* Pointer after last character printed. */
187 static int bufgap
; /* Weird flag indicating buflast is a lie. */
188 static unsigned long int buftotalnl
;
189 /* Count of newlines before last character. */
190 static int bufpending
; /* Lines of pending output at buflast. */
191 static int bufdesc
; /* File descriptor to read from. */
192 static int bufeof
; /* Flag indicating EOF reached. */
193 static const char *buffile
; /* File name for messages. */
195 /* Scan and count the newlines prior to LIM in the buffer. */
197 DEFUN(nlscan
, (lim
), register char *lim
)
201 for (p
= buflast
; p
< lim
; ++p
)
207 /* Print the line beginning at BEG, using SEP to separate optional label
208 fields from the text of the line. Return the size of the line. */
210 DEFUN(prline
, (beg
, sep
), register char *beg AND
register char sep
)
218 if (out_silent
|| err
)
228 printf("%s%c", buffile
, sep
);
232 printf("%d%c", buftotalnl
+ 1, sep
);
235 printf("%lu%c", buftotalcc
+ (beg
- buf
), sep
);
246 error("output error", errno
);
260 /* Print pending bytes of last trailing context prior to LIM. */
262 DEFUN(prpending
, (lim
), register char *lim
)
264 while (buflast
< lim
&& bufpending
)
267 prline(buflast
, '-');
271 /* Print the lines between BEG and LIM. Deal with context crap.
272 Return the count of lines between BEG and LIM. */
274 DEFUN(prtext
, (beg
, lim
), char *beg AND
char *lim
)
283 for (i
= 0; i
< out_before
; ++i
)
287 while (p
> buflast
&& p
[-1] != '\n');
289 if ((out_before
|| out_after
) && used
&& (p
> buflast
|| bufgap
))
302 bufpending
= out_after
;
308 /* Fill the user-visible portion of the buffer, returning a byte count. */
312 register char *b
, *d
, *l
;
314 size_t discard
, save
;
319 for (i
= 0; i
< out_before
; ++i
)
323 while (b
> buflast
&& b
[-1] != '\n');
342 buftotalcc
+= discard
;
348 if (bufcc
> bufalloc
/ 2)
349 buf
= xrealloc(buf
, bufalloc
*= 2);
350 cc
= read(bufdesc
, buf
+ bufcc
, bufalloc
- bufcc
);
353 error(buffile
, errno
);
363 for (l
= buf
+ bufcc
; l
> bufbeg
&& l
[-1] != '\n'; --l
)
368 while (!bufeof
&& bufbeg
== buflim
);
371 buflim
= buf
+ bufcc
;
373 return buflim
- bufbeg
;
376 /* One-time initialization. */
381 buf
= xmalloc(bufalloc
);
384 /* Reset the buffer for a new file. */
386 DEFUN(resetbuf
, (desc
, file
), int desc AND
const char *file
)
401 /* Scan the user-visible portion of the buffer, calling prtext() for
402 matching lines (or between matching lines if OUT_INVERT is true).
403 Return a count of lines printed. */
408 register char *p
, *b
, *l
;
412 while (b
= execute(p
, buflim
- p
))
414 if (b
== buflim
&& (b
> bufbeg
&& b
[-1] == '\n' || b
== bufbeg
))
416 while (b
> bufbeg
&& b
[-1] != '\n')
419 while (l
< buflim
&& l
[-1] != '\n')
422 total
+= prtext(b
, l
);
424 total
+= prtext(p
, b
);
427 if (out_invert
&& p
< buflim
)
428 total
+= prtext(p
, buflim
);
432 /* Scan the given file, returning a count of lines printed. */
434 DEFUN(grep
, (desc
, file
), int desc AND
const char *file
)
439 resetbuf(desc
, file
);
445 static const char version
[] = "GNU fgrep, version 1.1";
448 "usage: %s [-[[AB] ]<num>] [-[CVchilnsvwx]] [-[ef]] <expr> [<files...>]\n"
453 fprintf(stderr
, USAGE
, prog
);
458 DEFUN(main
, (argc
, argv
), int argc AND
char *argv
[])
461 size_t keycc
, keyalloc
;
462 int count_matches
, no_filenames
, list_files
;
463 int opt
, cc
, desc
, count
, status
;
467 if (prog
&& strrchr(prog
, '/'))
468 prog
= strrchr(prog
, '/') + 1;
475 while ((opt
= getopt(argc
, argv
, "0123456789A:B:CVbce:f:hilnsvwxy")) != EOF
)
488 out_before
= 10 * out_before
+ opt
- '0';
489 out_after
= 10 * out_after
+ opt
- '0';
492 out_after
= atoi(optarg
);
497 out_before
= atoi(optarg
);
502 out_before
= out_after
= 2;
505 fprintf(stderr
, "%s\n", version
);
518 keycc
= strlen(keys
);
523 fp
= strcmp(optarg
, "-") ? fopen(optarg
, "r") : stdin
;
525 fatal(optarg
, errno
);
527 keys
= xmalloc(keyalloc
);
530 && (cc
= fread(keys
+ keycc
, 1, keyalloc
- keycc
, fp
)) > 0)
533 if (keycc
== keyalloc
)
534 keys
= xrealloc(keys
, keyalloc
*= 2);
543 case 'y': /* For old-timers . . . */
573 keys
= argv
[optind
++];
574 keycc
= strlen(keys
);
579 compile(keys
, keycc
);
581 if (argc
- optind
> 1 && !no_filenames
)
588 while (optind
< argc
)
590 desc
= strcmp(argv
[optind
], "-") ? open(argv
[optind
], 0) : 0;
592 error(argv
[optind
], errno
);
595 count
= grep(desc
, argv
[optind
]);
599 printf("%s:", argv
[optind
]);
600 printf("%d\n", count
);
606 printf("%s\n", argv
[optind
]);
615 count
= grep(0, "<stdin>");
617 printf("%d\n", count
);
622 printf("%s\n", argv
[optind
]);
626 exit(error_seen
? 2 : status
);