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