608
}
609
}
610
611
+static int should_lookahead(struct grep_opt *opt)
612
+{
613
+ struct grep_pat *p;
614
+
615
+ if (opt->extended)
616
+ return 0; /* punt for too complex stuff */
617
+ if (opt->invert)
618
+ return 0;
619
+ for (p = opt->pattern_list; p; p = p->next) {
620
+ if (p->token != GREP_PATTERN)
621
+ return 0; /* punt for "header only" and stuff */
622
+ }
623
+ return 1;
624
+}
625
+
626
+static int look_ahead(struct grep_opt *opt,
627
+ unsigned long *left_p,
628
+ unsigned *lno_p,
629
+ char **bol_p)
630
+{
631
+ unsigned lno = *lno_p;
632
+ char *bol = *bol_p;
633
+ struct grep_pat *p;
634
+ char *sp, *last_bol;
635
+ regoff_t earliest = -1;
636
+
637
+ for (p = opt->pattern_list; p; p = p->next) {
638
+ int hit;
639
+ regmatch_t m;
640
+
641
+ if (p->fixed)
642
+ hit = !fixmatch(p->pattern, bol, &m);
643
+ else
644
+ hit = !regexec(&p->regexp, bol, 1, &m, 0);
645
+ if (!hit || m.rm_so < 0 || m.rm_eo < 0)
646
+ continue;
647
+ if (earliest < 0 || m.rm_so < earliest)
648
+ earliest = m.rm_so;
649
+ }
650
+
651
+ if (earliest < 0) {
652
+ *bol_p = bol + *left_p;
653
+ *left_p = 0;
654
+ return 1;
655
+ }
656
+ for (sp = bol + earliest; bol < sp && sp[-1] != '\n'; sp--)
657
+ ; /* find the beginning of the line */
658
+ last_bol = sp;
659
+
660
+ for (sp = bol; sp < last_bol; sp++) {
661
+ if (*sp == '\n')
662
+ lno++;
663
+ }
664
+ *left_p -= last_bol - bol;
665
+ *bol_p = last_bol;
666
+ *lno_p = lno;
667
+ return 0;
668
+}
669
+
670
static int grep_buffer_1(struct grep_opt *opt, const char *name,
671
char *buf, unsigned long size, int collect_hits)
672
{
676
unsigned last_hit = 0;
677
int binary_match_only = 0;
678
unsigned count = 0;
679
+ int try_lookahead = 0;
680
enum grep_context ctx = GREP_CONTEXT_HEAD;
681
xdemitconf_t xecfg;
682
705
opt->priv = &xecfg;
706
}
707
}
708
+ try_lookahead = should_lookahead(opt);
709
710
while (left) {
711
char *eol, ch;
712
int hit;
713
714
+ /*
715
+ * look_ahead() skips quicly to the line that possibly
716
+ * has the next hit; don't call it if we need to do
717
+ * something more than just skipping the current line
718
+ * in response to an unmatch for the current line. E.g.
719
+ * inside a post-context window, we will show the current
720
+ * line as a context around the previous hit when it
721
+ * doesn't hit.
722
+ */
723
+ if (try_lookahead
724
+ && !(last_hit
725
+ && lno <= last_hit + opt->post_context)
726
+ && look_ahead(opt, &left, &lno, &bol))
727
+ break;
728
eol = end_of_line(bol, &left);
729
ch = *eol;
730
*eol = 0;