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