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