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