Deleted Added
full compact
util.c (224938) util.c (226035)
1/* $NetBSD: util.c,v 1.9 2011/02/27 17:33:37 joerg Exp $ */
1/* $NetBSD: util.c,v 1.9 2011/02/27 17:33:37 joerg Exp $ */
2/* $FreeBSD: head/usr.bin/grep/util.c 224938 2011-08-17 13:58:39Z gabor $ */
2/* $FreeBSD: head/usr.bin/grep/util.c 226035 2011-10-05 09:56:43Z gabor $ */
3/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
4
5/*-
6 * Copyright (c) 1999 James Howard and Dag-Erling Co��dan Sm��rgrav
7 * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
3/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
4
5/*-
6 * Copyright (c) 1999 James Howard and Dag-Erling Co��dan Sm��rgrav
7 * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/usr.bin/grep/util.c 224938 2011-08-17 13:58:39Z gabor $");
33__FBSDID("$FreeBSD: head/usr.bin/grep/util.c 226035 2011-10-05 09:56:43Z gabor $");
34
35#include <sys/stat.h>
36#include <sys/types.h>
37
38#include <ctype.h>
39#include <err.h>
40#include <errno.h>
41#include <fnmatch.h>
42#include <fts.h>
43#include <libgen.h>
44#include <stdbool.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49#include <wchar.h>
50#include <wctype.h>
51
34
35#include <sys/stat.h>
36#include <sys/types.h>
37
38#include <ctype.h>
39#include <err.h>
40#include <errno.h>
41#include <fnmatch.h>
42#include <fts.h>
43#include <libgen.h>
44#include <stdbool.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49#include <wchar.h>
50#include <wctype.h>
51
52#include "fastmatch.h"
52#include "grep.h"
53
54static int linesqueued;
55static int procline(struct str *l, int);
56
57bool
58file_matching(const char *fname)
59{
60 char *fname_base;
61 bool ret;
62
63 ret = finclude ? false : true;
64 fname_base = basename(fname);
65
66 for (unsigned int i = 0; i < fpatterns; ++i) {
67 if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
68 fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
69 if (fpattern[i].mode == EXCL_PAT)
70 return (false);
71 else
72 ret = true;
73 }
74 }
75 return (ret);
76}
77
78static inline bool
79dir_matching(const char *dname)
80{
81 bool ret;
82
83 ret = dinclude ? false : true;
84
85 for (unsigned int i = 0; i < dpatterns; ++i) {
86 if (dname != NULL &&
87 fnmatch(dpattern[i].pat, dname, 0) == 0) {
88 if (dpattern[i].mode == EXCL_PAT)
89 return (false);
90 else
91 ret = true;
92 }
93 }
94 return (ret);
95}
96
97/*
98 * Processes a directory when a recursive search is performed with
99 * the -R option. Each appropriate file is passed to procfile().
100 */
101int
102grep_tree(char **argv)
103{
104 FTS *fts;
105 FTSENT *p;
106 int c, fts_flags;
107 bool ok;
108
109 c = fts_flags = 0;
110
111 switch(linkbehave) {
112 case LINK_EXPLICIT:
113 fts_flags = FTS_COMFOLLOW;
114 break;
115 case LINK_SKIP:
116 fts_flags = FTS_PHYSICAL;
117 break;
118 default:
119 fts_flags = FTS_LOGICAL;
120
121 }
122
123 fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
124
125 if (!(fts = fts_open(argv, fts_flags, NULL)))
126 err(2, "fts_open");
127 while ((p = fts_read(fts)) != NULL) {
128 switch (p->fts_info) {
129 case FTS_DNR:
130 /* FALLTHROUGH */
131 case FTS_ERR:
132 errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
133 break;
134 case FTS_D:
135 /* FALLTHROUGH */
136 case FTS_DP:
137 if (dexclude || dinclude)
138 if (!dir_matching(p->fts_name) ||
139 !dir_matching(p->fts_path))
140 fts_set(fts, p, FTS_SKIP);
141 break;
142 case FTS_DC:
143 /* Print a warning for recursive directory loop */
144 warnx("warning: %s: recursive directory loop",
145 p->fts_path);
146 break;
147 default:
148 /* Check for file exclusion/inclusion */
149 ok = true;
150 if (fexclude || finclude)
151 ok &= file_matching(p->fts_path);
152
153 if (ok)
154 c += procfile(p->fts_path);
155 break;
156 }
157 }
158
159 fts_close(fts);
160 return (c);
161}
162
163/*
164 * Opens a file and processes it. Each file is processed line-by-line
165 * passing the lines to procline().
166 */
167int
168procfile(const char *fn)
169{
170 struct file *f;
171 struct stat sb;
172 struct str ln;
173 mode_t s;
174 int c, t;
175
176 if (mflag && (mcount <= 0))
177 return (0);
178
179 if (strcmp(fn, "-") == 0) {
180 fn = label != NULL ? label : getstr(1);
181 f = grep_open(NULL);
182 } else {
183 if (!stat(fn, &sb)) {
184 /* Check if we need to process the file */
185 s = sb.st_mode & S_IFMT;
186 if (s == S_IFDIR && dirbehave == DIR_SKIP)
187 return (0);
188 if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
189 || s == S_IFSOCK) && devbehave == DEV_SKIP)
190 return (0);
191 }
192 f = grep_open(fn);
193 }
194 if (f == NULL) {
195 if (!sflag)
196 warn("%s", fn);
197 if (errno == ENOENT)
198 notfound = true;
199 return (0);
200 }
201
202 ln.file = grep_malloc(strlen(fn) + 1);
203 strcpy(ln.file, fn);
204 ln.line_no = 0;
205 ln.len = 0;
206 linesqueued = 0;
207 tail = 0;
208 ln.off = -1;
209
210 for (c = 0; c == 0 || !(lflag || qflag); ) {
211 ln.off += ln.len + 1;
212 if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0) {
213 if (ln.line_no == 0 && matchall)
214 exit(0);
215 else
216 break;
217 }
218 if (ln.len > 0 && ln.dat[ln.len - 1] == '\n')
219 --ln.len;
220 ln.line_no++;
221
222 /* Return if we need to skip a binary file */
223 if (f->binary && binbehave == BINFILE_SKIP) {
224 grep_close(f);
225 free(ln.file);
226 free(f);
227 return (0);
228 }
229 /* Process the file line-by-line */
230 if ((t = procline(&ln, f->binary)) == 0 && Bflag > 0) {
231 enqueue(&ln);
232 linesqueued++;
233 }
234 c += t;
53#include "grep.h"
54
55static int linesqueued;
56static int procline(struct str *l, int);
57
58bool
59file_matching(const char *fname)
60{
61 char *fname_base;
62 bool ret;
63
64 ret = finclude ? false : true;
65 fname_base = basename(fname);
66
67 for (unsigned int i = 0; i < fpatterns; ++i) {
68 if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
69 fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
70 if (fpattern[i].mode == EXCL_PAT)
71 return (false);
72 else
73 ret = true;
74 }
75 }
76 return (ret);
77}
78
79static inline bool
80dir_matching(const char *dname)
81{
82 bool ret;
83
84 ret = dinclude ? false : true;
85
86 for (unsigned int i = 0; i < dpatterns; ++i) {
87 if (dname != NULL &&
88 fnmatch(dpattern[i].pat, dname, 0) == 0) {
89 if (dpattern[i].mode == EXCL_PAT)
90 return (false);
91 else
92 ret = true;
93 }
94 }
95 return (ret);
96}
97
98/*
99 * Processes a directory when a recursive search is performed with
100 * the -R option. Each appropriate file is passed to procfile().
101 */
102int
103grep_tree(char **argv)
104{
105 FTS *fts;
106 FTSENT *p;
107 int c, fts_flags;
108 bool ok;
109
110 c = fts_flags = 0;
111
112 switch(linkbehave) {
113 case LINK_EXPLICIT:
114 fts_flags = FTS_COMFOLLOW;
115 break;
116 case LINK_SKIP:
117 fts_flags = FTS_PHYSICAL;
118 break;
119 default:
120 fts_flags = FTS_LOGICAL;
121
122 }
123
124 fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
125
126 if (!(fts = fts_open(argv, fts_flags, NULL)))
127 err(2, "fts_open");
128 while ((p = fts_read(fts)) != NULL) {
129 switch (p->fts_info) {
130 case FTS_DNR:
131 /* FALLTHROUGH */
132 case FTS_ERR:
133 errx(2, "%s: %s", p->fts_path, strerror(p->fts_errno));
134 break;
135 case FTS_D:
136 /* FALLTHROUGH */
137 case FTS_DP:
138 if (dexclude || dinclude)
139 if (!dir_matching(p->fts_name) ||
140 !dir_matching(p->fts_path))
141 fts_set(fts, p, FTS_SKIP);
142 break;
143 case FTS_DC:
144 /* Print a warning for recursive directory loop */
145 warnx("warning: %s: recursive directory loop",
146 p->fts_path);
147 break;
148 default:
149 /* Check for file exclusion/inclusion */
150 ok = true;
151 if (fexclude || finclude)
152 ok &= file_matching(p->fts_path);
153
154 if (ok)
155 c += procfile(p->fts_path);
156 break;
157 }
158 }
159
160 fts_close(fts);
161 return (c);
162}
163
164/*
165 * Opens a file and processes it. Each file is processed line-by-line
166 * passing the lines to procline().
167 */
168int
169procfile(const char *fn)
170{
171 struct file *f;
172 struct stat sb;
173 struct str ln;
174 mode_t s;
175 int c, t;
176
177 if (mflag && (mcount <= 0))
178 return (0);
179
180 if (strcmp(fn, "-") == 0) {
181 fn = label != NULL ? label : getstr(1);
182 f = grep_open(NULL);
183 } else {
184 if (!stat(fn, &sb)) {
185 /* Check if we need to process the file */
186 s = sb.st_mode & S_IFMT;
187 if (s == S_IFDIR && dirbehave == DIR_SKIP)
188 return (0);
189 if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
190 || s == S_IFSOCK) && devbehave == DEV_SKIP)
191 return (0);
192 }
193 f = grep_open(fn);
194 }
195 if (f == NULL) {
196 if (!sflag)
197 warn("%s", fn);
198 if (errno == ENOENT)
199 notfound = true;
200 return (0);
201 }
202
203 ln.file = grep_malloc(strlen(fn) + 1);
204 strcpy(ln.file, fn);
205 ln.line_no = 0;
206 ln.len = 0;
207 linesqueued = 0;
208 tail = 0;
209 ln.off = -1;
210
211 for (c = 0; c == 0 || !(lflag || qflag); ) {
212 ln.off += ln.len + 1;
213 if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0) {
214 if (ln.line_no == 0 && matchall)
215 exit(0);
216 else
217 break;
218 }
219 if (ln.len > 0 && ln.dat[ln.len - 1] == '\n')
220 --ln.len;
221 ln.line_no++;
222
223 /* Return if we need to skip a binary file */
224 if (f->binary && binbehave == BINFILE_SKIP) {
225 grep_close(f);
226 free(ln.file);
227 free(f);
228 return (0);
229 }
230 /* Process the file line-by-line */
231 if ((t = procline(&ln, f->binary)) == 0 && Bflag > 0) {
232 enqueue(&ln);
233 linesqueued++;
234 }
235 c += t;
235
236 /* Count the matches if we have a match limit */
237 if (mflag) {
238 mcount -= t;
239 if (mcount <= 0)
240 break;
241 }
236 if (mflag && mcount < 0)
237 break;
242 }
243 if (Bflag > 0)
244 clearqueue();
245 grep_close(f);
246
247 if (cflag) {
248 if (!hflag)
249 printf("%s:", ln.file);
250 printf("%u\n", c);
251 }
252 if (lflag && !qflag && c != 0)
253 printf("%s\n", fn);
254 if (Lflag && !qflag && c == 0)
255 printf("%s\n", fn);
256 if (c && !cflag && !lflag && !Lflag &&
257 binbehave == BINFILE_BIN && f->binary && !qflag)
258 printf(getstr(8), fn);
259
260 free(ln.file);
261 free(f);
262 return (c);
263}
264
265#define iswword(x) (iswalnum((x)) || (x) == L'_')
266
267/*
268 * Processes a line comparing it with the specified patterns. Each pattern
269 * is looped to be compared along with the full string, saving each and every
270 * match, which is necessary to colorize the output and to count the
271 * matches. The matching lines are passed to printline() to display the
272 * appropriate output.
273 */
274static int
275procline(struct str *l, int nottext)
276{
277 regmatch_t matches[MAX_LINE_MATCHES];
278 regmatch_t pmatch;
279 size_t st = 0;
280 unsigned int i;
281 int c = 0, m = 0, r = 0;
282
238 }
239 if (Bflag > 0)
240 clearqueue();
241 grep_close(f);
242
243 if (cflag) {
244 if (!hflag)
245 printf("%s:", ln.file);
246 printf("%u\n", c);
247 }
248 if (lflag && !qflag && c != 0)
249 printf("%s\n", fn);
250 if (Lflag && !qflag && c == 0)
251 printf("%s\n", fn);
252 if (c && !cflag && !lflag && !Lflag &&
253 binbehave == BINFILE_BIN && f->binary && !qflag)
254 printf(getstr(8), fn);
255
256 free(ln.file);
257 free(f);
258 return (c);
259}
260
261#define iswword(x) (iswalnum((x)) || (x) == L'_')
262
263/*
264 * Processes a line comparing it with the specified patterns. Each pattern
265 * is looped to be compared along with the full string, saving each and every
266 * match, which is necessary to colorize the output and to count the
267 * matches. The matching lines are passed to printline() to display the
268 * appropriate output.
269 */
270static int
271procline(struct str *l, int nottext)
272{
273 regmatch_t matches[MAX_LINE_MATCHES];
274 regmatch_t pmatch;
275 size_t st = 0;
276 unsigned int i;
277 int c = 0, m = 0, r = 0;
278
283 if (!matchall) {
284 /* Loop to process the whole line */
285 while (st <= l->len) {
286 pmatch.rm_so = st;
287 pmatch.rm_eo = l->len;
279 /* Loop to process the whole line */
280 while (st <= l->len) {
281 pmatch.rm_so = st;
282 pmatch.rm_eo = l->len;
288
283
289 /* Loop to compare with all the patterns */
290 for (i = 0; i < patterns; i++) {
291/*
292 * XXX: grep_search() is a workaround for speed up and should be
293 * removed in the future. See fastgrep.c.
294 */
295 if (fg_pattern[i].pattern)
296 r = grep_search(&fg_pattern[i],
297 (unsigned char *)l->dat,
298 l->len, &pmatch);
299 else
300 r = regexec(&r_pattern[i], l->dat, 1,
301 &pmatch, eflags);
302 r = (r == 0) ? 0 : REG_NOMATCH;
303 st = (cflags & REG_NOSUB)
304 ? (size_t)l->len
305 : (size_t)pmatch.rm_eo;
306 if (r == REG_NOMATCH)
307 continue;
308 /* Check for full match */
309 if (r == 0 && xflag)
310 if (pmatch.rm_so != 0 ||
311 (size_t)pmatch.rm_eo != l->len)
312 r = REG_NOMATCH;
313 /* Check for whole word match */
314 if (r == 0 && (wflag || fg_pattern[i].word)) {
315 wint_t wbegin, wend;
284 /* Loop to compare with all the patterns */
285 for (i = 0; i < patterns; i++) {
286 if (fg_pattern[i].pattern)
287 r = fastexec(&fg_pattern[i],
288 l->dat, 1, &pmatch, eflags);
289 else
290 r = regexec(&r_pattern[i], l->dat, 1,
291 &pmatch, eflags);
292 r = (r == 0) ? 0 : REG_NOMATCH;
293 st = (cflags & REG_NOSUB)
294 ? (size_t)l->len
295 : (size_t)pmatch.rm_eo;
296 if (r == REG_NOMATCH)
297 continue;
298 /* Check for full match */
299 if (r == 0 && xflag)
300 if (pmatch.rm_so != 0 ||
301 (size_t)pmatch.rm_eo != l->len)
302 r = REG_NOMATCH;
303 /* Check for whole word match */
304 if (r == 0 && (wflag || fg_pattern[i].word)) {
305 wint_t wbegin, wend;
316
306
317 wbegin = wend = L' ';
318 if (pmatch.rm_so != 0 &&
319 sscanf(&l->dat[pmatch.rm_so - 1],
320 "%lc", &wbegin) != 1)
321 r = REG_NOMATCH;
322 else if ((size_t)pmatch.rm_eo !=
323 l->len &&
324 sscanf(&l->dat[pmatch.rm_eo],
325 "%lc", &wend) != 1)
326 r = REG_NOMATCH;
327 else if (iswword(wbegin) ||
328 iswword(wend))
329 r = REG_NOMATCH;
330 }
331 if (r == 0) {
332 if (m == 0)
333 c++;
334 if (m < MAX_LINE_MATCHES)
335 matches[m++] = pmatch;
336 /* matches - skip further patterns */
337 if ((color == NULL && !oflag) ||
338 qflag || lflag)
339 break;
340 }
307 wbegin = wend = L' ';
308 if (pmatch.rm_so != 0 &&
309 sscanf(&l->dat[pmatch.rm_so - 1],
310 "%lc", &wbegin) != 1)
311 r = REG_NOMATCH;
312 else if ((size_t)pmatch.rm_eo !=
313 l->len &&
314 sscanf(&l->dat[pmatch.rm_eo],
315 "%lc", &wend) != 1)
316 r = REG_NOMATCH;
317 else if (iswword(wbegin) ||
318 iswword(wend))
319 r = REG_NOMATCH;
341 }
320 }
342
343 if (vflag) {
344 c = !c;
345 break;
321 if (r == 0) {
322 if (m == 0)
323 c++;
324 if (m < MAX_LINE_MATCHES)
325 matches[m++] = pmatch;
326 /* matches - skip further patterns */
327 if ((color == NULL && !oflag) ||
328 qflag || lflag)
329 break;
346 }
330 }
347 /* One pass if we are not recording matches */
348 if ((color == NULL && !oflag) || qflag || lflag)
349 break;
331 }
350
332
351 if (st == (size_t)pmatch.rm_so)
352 break; /* No matches */
333 if (vflag) {
334 c = !c;
335 break;
353 }
336 }
354 } else
355 c = !vflag;
356
337
338 /* One pass if we are not recording matches */
339 if ((color == NULL && !oflag) || qflag || lflag)
340 break;
341
342 if (st == (size_t)pmatch.rm_so)
343 break; /* No matches */
344 }
345
346
347 /* Count the matches if we have a match limit */
348 if (mflag)
349 mcount -= c;
350
357 if (c && binbehave == BINFILE_BIN && nottext)
358 return (c); /* Binary file */
359
360 /* Dealing with the context */
361 if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
362 if (c) {
363 if (!first && !prev && !tail && Aflag)
364 printf("--\n");
365 tail = Aflag;
366 if (Bflag > 0) {
367 if (!first && !prev)
368 printf("--\n");
369 printqueue();
370 }
371 linesqueued = 0;
372 printline(l, ':', matches, m);
373 } else {
374 printline(l, '-', matches, m);
375 tail--;
376 }
377 }
378
379 if (c) {
380 prev = true;
381 first = false;
382 } else
383 prev = false;
384
385 return (c);
386}
387
388/*
389 * Safe malloc() for internal use.
390 */
391void *
392grep_malloc(size_t size)
393{
394 void *ptr;
395
396 if ((ptr = malloc(size)) == NULL)
397 err(2, "malloc");
398 return (ptr);
399}
400
401/*
402 * Safe calloc() for internal use.
403 */
404void *
405grep_calloc(size_t nmemb, size_t size)
406{
407 void *ptr;
408
409 if ((ptr = calloc(nmemb, size)) == NULL)
410 err(2, "calloc");
411 return (ptr);
412}
413
414/*
415 * Safe realloc() for internal use.
416 */
417void *
418grep_realloc(void *ptr, size_t size)
419{
420
421 if ((ptr = realloc(ptr, size)) == NULL)
422 err(2, "realloc");
423 return (ptr);
424}
425
426/*
427 * Safe strdup() for internal use.
428 */
429char *
430grep_strdup(const char *str)
431{
432 char *ret;
433
434 if ((ret = strdup(str)) == NULL)
435 err(2, "strdup");
436 return (ret);
437}
438
439/*
440 * Prints a matching line according to the command line options.
441 */
442void
443printline(struct str *line, int sep, regmatch_t *matches, int m)
444{
445 size_t a = 0;
446 int i, n = 0;
447
448 if (!hflag) {
449 if (nullflag == 0)
450 fputs(line->file, stdout);
451 else {
452 printf("%s", line->file);
453 putchar(0);
454 }
455 ++n;
456 }
457 if (nflag) {
458 if (n > 0)
459 putchar(sep);
460 printf("%d", line->line_no);
461 ++n;
462 }
463 if (bflag) {
464 if (n > 0)
465 putchar(sep);
466 printf("%lld", (long long)line->off);
467 ++n;
468 }
469 if (n)
470 putchar(sep);
471 /* --color and -o */
472 if ((oflag || color) && m > 0) {
473 for (i = 0; i < m; i++) {
474 if (!oflag)
475 fwrite(line->dat + a, matches[i].rm_so - a, 1,
476 stdout);
477 if (color)
478 fprintf(stdout, "\33[%sm\33[K", color);
479
480 fwrite(line->dat + matches[i].rm_so,
481 matches[i].rm_eo - matches[i].rm_so, 1,
482 stdout);
483 if (color)
484 fprintf(stdout, "\33[m\33[K");
485 a = matches[i].rm_eo;
486 if (oflag)
487 putchar('\n');
488 }
489 if (!oflag) {
490 if (line->len - a > 0)
491 fwrite(line->dat + a, line->len - a, 1, stdout);
492 putchar('\n');
493 }
494 } else {
495 fwrite(line->dat, line->len, 1, stdout);
496 putchar('\n');
497 }
498}
351 if (c && binbehave == BINFILE_BIN && nottext)
352 return (c); /* Binary file */
353
354 /* Dealing with the context */
355 if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
356 if (c) {
357 if (!first && !prev && !tail && Aflag)
358 printf("--\n");
359 tail = Aflag;
360 if (Bflag > 0) {
361 if (!first && !prev)
362 printf("--\n");
363 printqueue();
364 }
365 linesqueued = 0;
366 printline(l, ':', matches, m);
367 } else {
368 printline(l, '-', matches, m);
369 tail--;
370 }
371 }
372
373 if (c) {
374 prev = true;
375 first = false;
376 } else
377 prev = false;
378
379 return (c);
380}
381
382/*
383 * Safe malloc() for internal use.
384 */
385void *
386grep_malloc(size_t size)
387{
388 void *ptr;
389
390 if ((ptr = malloc(size)) == NULL)
391 err(2, "malloc");
392 return (ptr);
393}
394
395/*
396 * Safe calloc() for internal use.
397 */
398void *
399grep_calloc(size_t nmemb, size_t size)
400{
401 void *ptr;
402
403 if ((ptr = calloc(nmemb, size)) == NULL)
404 err(2, "calloc");
405 return (ptr);
406}
407
408/*
409 * Safe realloc() for internal use.
410 */
411void *
412grep_realloc(void *ptr, size_t size)
413{
414
415 if ((ptr = realloc(ptr, size)) == NULL)
416 err(2, "realloc");
417 return (ptr);
418}
419
420/*
421 * Safe strdup() for internal use.
422 */
423char *
424grep_strdup(const char *str)
425{
426 char *ret;
427
428 if ((ret = strdup(str)) == NULL)
429 err(2, "strdup");
430 return (ret);
431}
432
433/*
434 * Prints a matching line according to the command line options.
435 */
436void
437printline(struct str *line, int sep, regmatch_t *matches, int m)
438{
439 size_t a = 0;
440 int i, n = 0;
441
442 if (!hflag) {
443 if (nullflag == 0)
444 fputs(line->file, stdout);
445 else {
446 printf("%s", line->file);
447 putchar(0);
448 }
449 ++n;
450 }
451 if (nflag) {
452 if (n > 0)
453 putchar(sep);
454 printf("%d", line->line_no);
455 ++n;
456 }
457 if (bflag) {
458 if (n > 0)
459 putchar(sep);
460 printf("%lld", (long long)line->off);
461 ++n;
462 }
463 if (n)
464 putchar(sep);
465 /* --color and -o */
466 if ((oflag || color) && m > 0) {
467 for (i = 0; i < m; i++) {
468 if (!oflag)
469 fwrite(line->dat + a, matches[i].rm_so - a, 1,
470 stdout);
471 if (color)
472 fprintf(stdout, "\33[%sm\33[K", color);
473
474 fwrite(line->dat + matches[i].rm_so,
475 matches[i].rm_eo - matches[i].rm_so, 1,
476 stdout);
477 if (color)
478 fprintf(stdout, "\33[m\33[K");
479 a = matches[i].rm_eo;
480 if (oflag)
481 putchar('\n');
482 }
483 if (!oflag) {
484 if (line->len - a > 0)
485 fwrite(line->dat + a, line->len - a, 1, stdout);
486 putchar('\n');
487 }
488 } else {
489 fwrite(line->dat, line->len, 1, stdout);
490 putchar('\n');
491 }
492}