1/*	$NetBSD: util.c,v 1.9 2011/02/27 17:33:37 joerg Exp $	*/
2/*	$OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $	*/
3
4/*-
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * Copyright (c) 1999 James Howard and Dag-Erling Sm��rgrav
8 * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
9 * Copyright (C) 2017 Kyle Evans <kevans@FreeBSD.org>
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
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 "grep.h"
53
54static bool	 first_match = true;
55
56/*
57 * Match printing context
58 */
59struct mprintc {
60	long long	tail;		/* Number of trailing lines to record */
61	int		last_outed;	/* Number of lines since last output */
62	bool		doctx;		/* Printing context? */
63	bool		printmatch;	/* Printing matches? */
64	bool		same_file;	/* Same file as previously printed? */
65};
66
67static void procmatch_match(struct mprintc *mc, struct parsec *pc);
68static void procmatch_nomatch(struct mprintc *mc, struct parsec *pc);
69static bool procmatches(struct mprintc *mc, struct parsec *pc, bool matched);
70#ifdef WITH_INTERNAL_NOSPEC
71static int litexec(const struct pat *pat, const char *string,
72    size_t nmatch, regmatch_t pmatch[]);
73#endif
74static bool procline(struct parsec *pc);
75static void printline(struct parsec *pc, int sep);
76static void printline_metadata(struct str *line, int sep);
77
78bool
79file_matching(const char *fname)
80{
81	char *fname_base, *fname_buf;
82	bool ret;
83
84	ret = finclude ? false : true;
85	fname_buf = strdup(fname);
86	if (fname_buf == NULL)
87		err(2, "strdup");
88	fname_base = basename(fname_buf);
89
90	for (unsigned int i = 0; i < fpatterns; ++i) {
91		if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
92		    fnmatch(fpattern[i].pat, fname_base, 0) == 0)
93			/*
94			 * The last pattern matched wins exclusion/inclusion
95			 * rights, so we can't reasonably bail out early here.
96			 */
97			ret = (fpattern[i].mode != EXCL_PAT);
98	}
99	free(fname_buf);
100	return (ret);
101}
102
103static inline bool
104dir_matching(const char *dname)
105{
106	bool ret;
107
108	ret = dinclude ? false : true;
109
110	for (unsigned int i = 0; i < dpatterns; ++i) {
111		if (dname != NULL && fnmatch(dpattern[i].pat, dname, 0) == 0)
112			/*
113			 * The last pattern matched wins exclusion/inclusion
114			 * rights, so we can't reasonably bail out early here.
115			 */
116			ret = (dpattern[i].mode != EXCL_PAT);
117	}
118	return (ret);
119}
120
121/*
122 * Processes a directory when a recursive search is performed with
123 * the -R option.  Each appropriate file is passed to procfile().
124 */
125bool
126grep_tree(char **argv)
127{
128	FTS *fts;
129	FTSENT *p;
130	int fts_flags;
131	bool matched, ok;
132	const char *wd[] = { ".", NULL };
133
134	matched = false;
135
136	/* This switch effectively initializes 'fts_flags' */
137	switch(linkbehave) {
138	case LINK_EXPLICIT:
139		fts_flags = FTS_COMFOLLOW;
140		break;
141	case LINK_SKIP:
142		fts_flags = FTS_PHYSICAL;
143		break;
144	default:
145		fts_flags = FTS_LOGICAL;
146	}
147
148	fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
149
150	fts = fts_open((argv[0] == NULL) ?
151	    __DECONST(char * const *, wd) : argv, fts_flags, NULL);
152	if (fts == NULL)
153		err(2, "fts_open");
154	while (errno = 0, (p = fts_read(fts)) != NULL) {
155		switch (p->fts_info) {
156		case FTS_DNR:
157			/* FALLTHROUGH */
158		case FTS_ERR:
159			file_err = true;
160			if(!sflag)
161				warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
162			break;
163		case FTS_D:
164			/* FALLTHROUGH */
165		case FTS_DP:
166			if (dexclude || dinclude)
167				if (!dir_matching(p->fts_name) ||
168				    !dir_matching(p->fts_path))
169					fts_set(fts, p, FTS_SKIP);
170			break;
171		case FTS_DC:
172			/* Print a warning for recursive directory loop */
173			warnx("warning: %s: recursive directory loop",
174			    p->fts_path);
175			break;
176		default:
177			/* Check for file exclusion/inclusion */
178			ok = true;
179			if (fexclude || finclude)
180				ok &= file_matching(p->fts_path);
181
182			if (ok && procfile(p->fts_path))
183				matched = true;
184			break;
185		}
186	}
187	if (errno != 0)
188		err(2, "fts_read");
189
190	fts_close(fts);
191	return (matched);
192}
193
194static void
195procmatch_match(struct mprintc *mc, struct parsec *pc)
196{
197
198	if (mc->doctx) {
199		if (!first_match && (!mc->same_file || mc->last_outed > 0))
200			printf("--\n");
201		if (Bflag > 0)
202			printqueue();
203		mc->tail = Aflag;
204	}
205
206	/* Print the matching line, but only if not quiet/binary */
207	if (mc->printmatch) {
208		printline(pc, ':');
209		while (pc->matchidx >= MAX_MATCHES) {
210			/* Reset matchidx and try again */
211			pc->matchidx = 0;
212			if (procline(pc) == !vflag)
213				printline(pc, ':');
214			else
215				break;
216		}
217		first_match = false;
218		mc->same_file = true;
219		mc->last_outed = 0;
220	}
221}
222
223static void
224procmatch_nomatch(struct mprintc *mc, struct parsec *pc)
225{
226
227	/* Deal with any -A context as needed */
228	if (mc->tail > 0) {
229		grep_printline(&pc->ln, '-');
230		mc->tail--;
231		if (Bflag > 0)
232			clearqueue();
233	} else if (Bflag == 0 || (Bflag > 0 && enqueue(&pc->ln)))
234		/*
235		 * Enqueue non-matching lines for -B context. If we're not
236		 * actually doing -B context or if the enqueue resulted in a
237		 * line being rotated out, then go ahead and increment
238		 * last_outed to signify a gap between context/match.
239		 */
240		++mc->last_outed;
241}
242
243/*
244 * Process any matches in the current parsing context, return a boolean
245 * indicating whether we should halt any further processing or not. 'true' to
246 * continue processing, 'false' to halt.
247 */
248static bool
249procmatches(struct mprintc *mc, struct parsec *pc, bool matched)
250{
251
252	if (mflag && mcount <= 0) {
253		/*
254		 * We already hit our match count, but we need to keep dumping
255		 * lines until we've lost our tail.
256		 */
257		grep_printline(&pc->ln, '-');
258		mc->tail--;
259		return (mc->tail != 0);
260	}
261
262	/*
263	 * XXX TODO: This should loop over pc->matches and handle things on a
264	 * line-by-line basis, setting up a `struct str` as needed.
265	 */
266	/* Deal with any -B context or context separators */
267	if (matched) {
268		procmatch_match(mc, pc);
269
270		/* Count the matches if we have a match limit */
271		if (mflag) {
272			/* XXX TODO: Decrement by number of matched lines */
273			mcount -= 1;
274			if (mcount <= 0)
275				return (mc->tail != 0);
276		}
277	} else if (mc->doctx)
278		procmatch_nomatch(mc, pc);
279
280	return (true);
281}
282
283/*
284 * Opens a file and processes it.  Each file is processed line-by-line
285 * passing the lines to procline().
286 */
287bool
288procfile(const char *fn)
289{
290	struct parsec pc;
291	struct mprintc mc;
292	struct file *f;
293	struct stat sb;
294	mode_t s;
295	int lines;
296	bool line_matched;
297
298	if (strcmp(fn, "-") == 0) {
299		fn = label != NULL ? label : errstr[1];
300		f = grep_open(NULL);
301	} else {
302		if (stat(fn, &sb) == 0) {
303			/* Check if we need to process the file */
304			s = sb.st_mode & S_IFMT;
305			if (dirbehave == DIR_SKIP && s == S_IFDIR)
306				return (false);
307			if (devbehave == DEV_SKIP && (s == S_IFIFO ||
308			    s == S_IFCHR || s == S_IFBLK || s == S_IFSOCK))
309				return (false);
310		}
311		f = grep_open(fn);
312	}
313	if (f == NULL) {
314		file_err = true;
315		if (!sflag)
316			warn("%s", fn);
317		return (false);
318	}
319
320	pc.ln.file = grep_strdup(fn);
321	pc.ln.line_no = 0;
322	pc.ln.len = 0;
323	pc.ln.boff = 0;
324	pc.ln.off = -1;
325	pc.binary = f->binary;
326	pc.cntlines = false;
327	memset(&mc, 0, sizeof(mc));
328	mc.printmatch = true;
329	if ((pc.binary && binbehave == BINFILE_BIN) || cflag || qflag ||
330	    lflag || Lflag)
331		mc.printmatch = false;
332	if (mc.printmatch && (Aflag != 0 || Bflag != 0))
333		mc.doctx = true;
334	if (mc.printmatch && (Aflag != 0 || Bflag != 0 || mflag || nflag))
335		pc.cntlines = true;
336	mcount = mlimit;
337
338	for (lines = 0; lines == 0 || !(lflag || qflag); ) {
339		/*
340		 * XXX TODO: We need to revisit this in a chunking world. We're
341		 * not going to be doing per-line statistics because of the
342		 * overhead involved. procmatches can figure that stuff out as
343		 * needed. */
344		/* Reset per-line statistics */
345		pc.printed = 0;
346		pc.matchidx = 0;
347		pc.lnstart = 0;
348		pc.ln.boff = 0;
349		pc.ln.off += pc.ln.len + 1;
350		/* XXX TODO: Grab a chunk */
351		if ((pc.ln.dat = grep_fgetln(f, &pc)) == NULL ||
352		    pc.ln.len == 0)
353			break;
354
355		if (pc.ln.len > 0 && pc.ln.dat[pc.ln.len - 1] == fileeol)
356			--pc.ln.len;
357		pc.ln.line_no++;
358
359		/* Return if we need to skip a binary file */
360		if (pc.binary && binbehave == BINFILE_SKIP) {
361			grep_close(f);
362			free(pc.ln.file);
363			free(f);
364			return (0);
365		}
366
367		if (mflag && mcount <= 0) {
368			/*
369			 * Short-circuit, already hit match count and now we're
370			 * just picking up any remaining pieces.
371			 */
372			if (!procmatches(&mc, &pc, false))
373				break;
374			continue;
375		}
376		line_matched = procline(&pc) == !vflag;
377		if (line_matched)
378			++lines;
379
380		/* Halt processing if we hit our match limit */
381		if (!procmatches(&mc, &pc, line_matched))
382			break;
383	}
384	if (Bflag > 0)
385		clearqueue();
386	grep_close(f);
387
388	if (cflag && !qflag) {
389		if (!hflag)
390			printf("%s:", pc.ln.file);
391		printf("%u\n", lines);
392	}
393	if (lflag && !qflag && lines != 0)
394		printf("%s%c", fn, nullflag ? 0 : '\n');
395	if (Lflag && !qflag && lines == 0)
396		printf("%s%c", fn, nullflag ? 0 : '\n');
397	if (lines != 0 && !cflag && !lflag && !Lflag &&
398	    binbehave == BINFILE_BIN && f->binary && !qflag)
399		printf(errstr[7], fn);
400
401	free(pc.ln.file);
402	free(f);
403	return (lines != 0);
404}
405
406#ifdef WITH_INTERNAL_NOSPEC
407/*
408 * Internal implementation of literal string search within a string, modeled
409 * after regexec(3), for use when the regex(3) implementation doesn't offer
410 * either REG_NOSPEC or REG_LITERAL. This does not apply in the default FreeBSD
411 * config, but in other scenarios such as building against libgnuregex or on
412 * some non-FreeBSD OSes.
413 */
414static int
415litexec(const struct pat *pat, const char *string, size_t nmatch,
416    regmatch_t pmatch[])
417{
418	char *(*strstr_fn)(const char *, const char *);
419	char *sub, *subject;
420	const char *search;
421	size_t idx, n, ofs, stringlen;
422
423	if (cflags & REG_ICASE)
424		strstr_fn = strcasestr;
425	else
426		strstr_fn = strstr;
427	idx = 0;
428	ofs = pmatch[0].rm_so;
429	stringlen = pmatch[0].rm_eo;
430	if (ofs >= stringlen)
431		return (REG_NOMATCH);
432	subject = strndup(string, stringlen);
433	if (subject == NULL)
434		return (REG_ESPACE);
435	for (n = 0; ofs < stringlen;) {
436		search = (subject + ofs);
437		if ((unsigned long)pat->len > strlen(search))
438			break;
439		sub = strstr_fn(search, pat->pat);
440		/*
441		 * Ignoring the empty string possibility due to context: grep optimizes
442		 * for empty patterns and will never reach this point.
443		 */
444		if (sub == NULL)
445			break;
446		++n;
447		/* Fill in pmatch if necessary */
448		if (nmatch > 0) {
449			pmatch[idx].rm_so = ofs + (sub - search);
450			pmatch[idx].rm_eo = pmatch[idx].rm_so + pat->len;
451			if (++idx == nmatch)
452				break;
453			ofs = pmatch[idx].rm_so + 1;
454		} else
455			/* We only needed to know if we match or not */
456			break;
457	}
458	free(subject);
459	if (n > 0 && nmatch > 0)
460		for (n = idx; n < nmatch; ++n)
461			pmatch[n].rm_so = pmatch[n].rm_eo = -1;
462
463	return (n > 0 ? 0 : REG_NOMATCH);
464}
465#endif /* WITH_INTERNAL_NOSPEC */
466
467#define iswword(x)	(iswalnum((x)) || (x) == L'_')
468
469/*
470 * Processes a line comparing it with the specified patterns.  Each pattern
471 * is looped to be compared along with the full string, saving each and every
472 * match, which is necessary to colorize the output and to count the
473 * matches.  The matching lines are passed to printline() to display the
474 * appropriate output.
475 */
476static bool
477procline(struct parsec *pc)
478{
479	regmatch_t pmatch, lastmatch, chkmatch;
480	wchar_t wbegin, wend;
481	size_t st, nst;
482	unsigned int i;
483	int r = 0, leflags = eflags;
484	size_t startm = 0, matchidx;
485	unsigned int retry;
486	bool lastmatched, matched;
487
488	matchidx = pc->matchidx;
489
490	/* Null pattern shortcuts. */
491	if (matchall) {
492		if (xflag && pc->ln.len == 0) {
493			/* Matches empty lines (-x). */
494			return (true);
495		} else if (!wflag && !xflag) {
496			/* Matches every line (no -w or -x). */
497			return (true);
498		}
499
500		/*
501		 * If we only have the NULL pattern, whether we match or not
502		 * depends on if we got here with -w or -x.  If either is set,
503		 * the answer is no.  If we have other patterns, we'll defer
504		 * to them.
505		 */
506		if (patterns == 0) {
507			return (!(wflag || xflag));
508		}
509	} else if (patterns == 0) {
510		/* Pattern file with no patterns. */
511		return (false);
512	}
513
514	matched = false;
515	st = pc->lnstart;
516	nst = 0;
517	/* Initialize to avoid a false positive warning from GCC. */
518	lastmatch.rm_so = lastmatch.rm_eo = 0;
519
520	/* Loop to process the whole line */
521	while (st <= pc->ln.len) {
522		lastmatched = false;
523		startm = matchidx;
524		retry = 0;
525		if (st > 0 && pc->ln.dat[st - 1] != fileeol)
526			leflags |= REG_NOTBOL;
527		/* Loop to compare with all the patterns */
528		for (i = 0; i < patterns; i++) {
529			pmatch.rm_so = st;
530			pmatch.rm_eo = pc->ln.len;
531#ifdef WITH_INTERNAL_NOSPEC
532			if (grepbehave == GREP_FIXED)
533				r = litexec(&pattern[i], pc->ln.dat, 1, &pmatch);
534			else
535#endif
536			r = regexec(&r_pattern[i], pc->ln.dat, 1, &pmatch,
537			    leflags);
538			if (r != 0)
539				continue;
540			/* Check for full match */
541			if (xflag && (pmatch.rm_so != 0 ||
542			    (size_t)pmatch.rm_eo != pc->ln.len))
543				continue;
544			/* Check for whole word match */
545			if (wflag) {
546				wbegin = wend = L' ';
547				if (pmatch.rm_so != 0 &&
548				    sscanf(&pc->ln.dat[pmatch.rm_so - 1],
549				    "%lc", &wbegin) != 1)
550					r = REG_NOMATCH;
551				else if ((size_t)pmatch.rm_eo !=
552				    pc->ln.len &&
553				    sscanf(&pc->ln.dat[pmatch.rm_eo],
554				    "%lc", &wend) != 1)
555					r = REG_NOMATCH;
556				else if (iswword(wbegin) ||
557				    iswword(wend))
558					r = REG_NOMATCH;
559				/*
560				 * If we're doing whole word matching and we
561				 * matched once, then we should try the pattern
562				 * again after advancing just past the start of
563				 * the earliest match. This allows the pattern
564				 * to  match later on in the line and possibly
565				 * still match a whole word.
566				 */
567				if (r == REG_NOMATCH &&
568				    (retry == pc->lnstart ||
569				    (unsigned int)pmatch.rm_so + 1 < retry))
570					retry = pmatch.rm_so + 1;
571				if (r == REG_NOMATCH)
572					continue;
573			}
574			lastmatched = true;
575			lastmatch = pmatch;
576
577			if (matchidx == 0)
578				matched = true;
579
580			/*
581			 * Replace previous match if the new one is earlier
582			 * and/or longer. This will lead to some amount of
583			 * extra work if -o/--color are specified, but it's
584			 * worth it from a correctness point of view.
585			 */
586			if (matchidx > startm) {
587				chkmatch = pc->matches[matchidx - 1];
588				if (pmatch.rm_so < chkmatch.rm_so ||
589				    (pmatch.rm_so == chkmatch.rm_so &&
590				    (pmatch.rm_eo - pmatch.rm_so) >
591				    (chkmatch.rm_eo - chkmatch.rm_so))) {
592					pc->matches[matchidx - 1] = pmatch;
593					nst = pmatch.rm_eo;
594				}
595			} else {
596				/* Advance as normal if not */
597				pc->matches[matchidx++] = pmatch;
598				nst = pmatch.rm_eo;
599			}
600			/* avoid excessive matching - skip further patterns */
601			if ((color == NULL && !oflag) || qflag || lflag ||
602			    matchidx >= MAX_MATCHES) {
603				pc->lnstart = nst;
604				lastmatched = false;
605				break;
606			}
607		}
608
609		/*
610		 * Advance to just past the start of the earliest match, try
611		 * again just in case we still have a chance to match later in
612		 * the string.
613		 */
614		if (!lastmatched && retry > pc->lnstart) {
615			st = retry;
616			continue;
617		}
618
619		/* XXX TODO: We will need to keep going, since we're chunky */
620		/* One pass if we are not recording matches */
621		if (!wflag && ((color == NULL && !oflag) || qflag || lflag || Lflag))
622			break;
623
624		/* If we didn't have any matches or REG_NOSUB set */
625		if (!lastmatched || (cflags & REG_NOSUB))
626			nst = pc->ln.len;
627
628		if (!lastmatched)
629			/* No matches */
630			break;
631		else if (st == nst && lastmatch.rm_so == lastmatch.rm_eo)
632			/* Zero-length match -- advance one more so we don't get stuck */
633			nst++;
634
635		/* Advance st based on previous matches */
636		st = nst;
637		pc->lnstart = st;
638	}
639
640	/* Reflect the new matchidx in the context */
641	pc->matchidx = matchidx;
642	return matched;
643}
644
645/*
646 * Safe malloc() for internal use.
647 */
648void *
649grep_malloc(size_t size)
650{
651	void *ptr;
652
653	if (size == 0)
654		return (NULL);
655	if ((ptr = malloc(size)) == NULL)
656		err(2, "malloc");
657	return (ptr);
658}
659
660/*
661 * Safe calloc() for internal use.
662 */
663void *
664grep_calloc(size_t nmemb, size_t size)
665{
666	void *ptr;
667
668	if (nmemb == 0 || size == 0)
669		return (NULL);
670	if ((ptr = calloc(nmemb, size)) == NULL)
671		err(2, "calloc");
672	return (ptr);
673}
674
675/*
676 * Safe realloc() for internal use.
677 */
678void *
679grep_realloc(void *ptr, size_t size)
680{
681
682	if ((ptr = realloc(ptr, size)) == NULL)
683		err(2, "realloc");
684	return (ptr);
685}
686
687/*
688 * Safe strdup() for internal use.
689 */
690char *
691grep_strdup(const char *str)
692{
693	char *ret;
694
695	if ((ret = strdup(str)) == NULL)
696		err(2, "strdup");
697	return (ret);
698}
699
700/*
701 * Print an entire line as-is, there are no inline matches to consider. This is
702 * used for printing context.
703 */
704void grep_printline(struct str *line, int sep) {
705	printline_metadata(line, sep);
706	fwrite(line->dat, line->len, 1, stdout);
707	putchar(fileeol);
708}
709
710static void
711printline_metadata(struct str *line, int sep)
712{
713	bool printsep;
714
715	printsep = false;
716	if (!hflag) {
717		if (!nullflag) {
718			fputs(line->file, stdout);
719			printsep = true;
720		} else {
721			printf("%s", line->file);
722			putchar(0);
723		}
724	}
725	if (nflag) {
726		if (printsep)
727			putchar(sep);
728		printf("%d", line->line_no);
729		printsep = true;
730	}
731	if (bflag) {
732		if (printsep)
733			putchar(sep);
734		printf("%lld", (long long)(line->off + line->boff));
735		printsep = true;
736	}
737	if (printsep)
738		putchar(sep);
739}
740
741/*
742 * Prints a matching line according to the command line options.
743 */
744static void
745printline(struct parsec *pc, int sep)
746{
747	size_t a = 0;
748	size_t i, matchidx;
749	regmatch_t match;
750
751	/* If matchall, everything matches but don't actually print for -o */
752	if (oflag && matchall)
753		return;
754
755	matchidx = pc->matchidx;
756
757	/* --color and -o */
758	if ((oflag || color) && matchidx > 0) {
759		/* Only print metadata once per line if --color */
760		if (!oflag && pc->printed == 0)
761			printline_metadata(&pc->ln, sep);
762		for (i = 0; i < matchidx; i++) {
763			match = pc->matches[i];
764			/* Don't output zero length matches */
765			if (match.rm_so == match.rm_eo)
766				continue;
767			/*
768			 * Metadata is printed on a per-line basis, so every
769			 * match gets file metadata with the -o flag.
770			 */
771			if (oflag) {
772				pc->ln.boff = match.rm_so;
773				printline_metadata(&pc->ln, sep);
774			} else
775				fwrite(pc->ln.dat + a, match.rm_so - a, 1,
776				    stdout);
777			if (color)
778				fprintf(stdout, "\33[%sm\33[K", color);
779			fwrite(pc->ln.dat + match.rm_so,
780			    match.rm_eo - match.rm_so, 1, stdout);
781			if (color)
782				fprintf(stdout, "\33[m\33[K");
783			a = match.rm_eo;
784			if (oflag)
785				putchar('\n');
786		}
787		if (!oflag) {
788			if (pc->ln.len - a > 0)
789				fwrite(pc->ln.dat + a, pc->ln.len - a, 1,
790				    stdout);
791			putchar('\n');
792		}
793	} else
794		grep_printline(&pc->ln, sep);
795	pc->printed++;
796}
797