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