Code

grep: move logic to compile header pattern into a separate helper
[git.git] / grep.c
1 #include "cache.h"
2 #include "grep.h"
3 #include "userdiff.h"
4 #include "xdiff-interface.h"
6 void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)
7 {
8         struct grep_pat *p = xcalloc(1, sizeof(*p));
9         p->pattern = pat;
10         p->patternlen = strlen(pat);
11         p->origin = "header";
12         p->no = 0;
13         p->token = GREP_PATTERN_HEAD;
14         p->field = field;
15         *opt->header_tail = p;
16         opt->header_tail = &p->next;
17         p->next = NULL;
18 }
20 void append_grep_pattern(struct grep_opt *opt, const char *pat,
21                          const char *origin, int no, enum grep_pat_token t)
22 {
23         append_grep_pat(opt, pat, strlen(pat), origin, no, t);
24 }
26 void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen,
27                      const char *origin, int no, enum grep_pat_token t)
28 {
29         struct grep_pat *p = xcalloc(1, sizeof(*p));
30         p->pattern = pat;
31         p->patternlen = patlen;
32         p->origin = origin;
33         p->no = no;
34         p->token = t;
35         *opt->pattern_tail = p;
36         opt->pattern_tail = &p->next;
37         p->next = NULL;
38 }
40 struct grep_opt *grep_opt_dup(const struct grep_opt *opt)
41 {
42         struct grep_pat *pat;
43         struct grep_opt *ret = xmalloc(sizeof(struct grep_opt));
44         *ret = *opt;
46         ret->pattern_list = NULL;
47         ret->pattern_tail = &ret->pattern_list;
49         for(pat = opt->pattern_list; pat != NULL; pat = pat->next)
50         {
51                 if(pat->token == GREP_PATTERN_HEAD)
52                         append_header_grep_pattern(ret, pat->field,
53                                                    pat->pattern);
54                 else
55                         append_grep_pat(ret, pat->pattern, pat->patternlen,
56                                         pat->origin, pat->no, pat->token);
57         }
59         return ret;
60 }
62 static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
63 {
64         int err;
66         p->word_regexp = opt->word_regexp;
67         p->ignore_case = opt->ignore_case;
68         p->fixed = opt->fixed;
70         if (p->fixed)
71                 return;
73         err = regcomp(&p->regexp, p->pattern, opt->regflags);
74         if (err) {
75                 char errbuf[1024];
76                 char where[1024];
77                 if (p->no)
78                         sprintf(where, "In '%s' at %d, ",
79                                 p->origin, p->no);
80                 else if (p->origin)
81                         sprintf(where, "%s, ", p->origin);
82                 else
83                         where[0] = 0;
84                 regerror(err, &p->regexp, errbuf, 1024);
85                 regfree(&p->regexp);
86                 die("%s'%s': %s", where, p->pattern, errbuf);
87         }
88 }
90 static struct grep_expr *compile_pattern_or(struct grep_pat **);
91 static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
92 {
93         struct grep_pat *p;
94         struct grep_expr *x;
96         p = *list;
97         if (!p)
98                 return NULL;
99         switch (p->token) {
100         case GREP_PATTERN: /* atom */
101         case GREP_PATTERN_HEAD:
102         case GREP_PATTERN_BODY:
103                 x = xcalloc(1, sizeof (struct grep_expr));
104                 x->node = GREP_NODE_ATOM;
105                 x->u.atom = p;
106                 *list = p->next;
107                 return x;
108         case GREP_OPEN_PAREN:
109                 *list = p->next;
110                 x = compile_pattern_or(list);
111                 if (!*list || (*list)->token != GREP_CLOSE_PAREN)
112                         die("unmatched parenthesis");
113                 *list = (*list)->next;
114                 return x;
115         default:
116                 return NULL;
117         }
120 static struct grep_expr *compile_pattern_not(struct grep_pat **list)
122         struct grep_pat *p;
123         struct grep_expr *x;
125         p = *list;
126         if (!p)
127                 return NULL;
128         switch (p->token) {
129         case GREP_NOT:
130                 if (!p->next)
131                         die("--not not followed by pattern expression");
132                 *list = p->next;
133                 x = xcalloc(1, sizeof (struct grep_expr));
134                 x->node = GREP_NODE_NOT;
135                 x->u.unary = compile_pattern_not(list);
136                 if (!x->u.unary)
137                         die("--not followed by non pattern expression");
138                 return x;
139         default:
140                 return compile_pattern_atom(list);
141         }
144 static struct grep_expr *compile_pattern_and(struct grep_pat **list)
146         struct grep_pat *p;
147         struct grep_expr *x, *y, *z;
149         x = compile_pattern_not(list);
150         p = *list;
151         if (p && p->token == GREP_AND) {
152                 if (!p->next)
153                         die("--and not followed by pattern expression");
154                 *list = p->next;
155                 y = compile_pattern_and(list);
156                 if (!y)
157                         die("--and not followed by pattern expression");
158                 z = xcalloc(1, sizeof (struct grep_expr));
159                 z->node = GREP_NODE_AND;
160                 z->u.binary.left = x;
161                 z->u.binary.right = y;
162                 return z;
163         }
164         return x;
167 static struct grep_expr *compile_pattern_or(struct grep_pat **list)
169         struct grep_pat *p;
170         struct grep_expr *x, *y, *z;
172         x = compile_pattern_and(list);
173         p = *list;
174         if (x && p && p->token != GREP_CLOSE_PAREN) {
175                 y = compile_pattern_or(list);
176                 if (!y)
177                         die("not a pattern expression %s", p->pattern);
178                 z = xcalloc(1, sizeof (struct grep_expr));
179                 z->node = GREP_NODE_OR;
180                 z->u.binary.left = x;
181                 z->u.binary.right = y;
182                 return z;
183         }
184         return x;
187 static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
189         return compile_pattern_or(list);
192 static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
194         struct grep_pat *p;
195         struct grep_expr *header_expr;
197         if (!opt->header_list)
198                 return NULL;
199         p = opt->header_list;
200         header_expr = compile_pattern_expr(&p);
201         if (p)
202                 die("incomplete pattern expression: %s", p->pattern);
203         for (p = opt->header_list; p; p = p->next) {
204                 if (p->token != GREP_PATTERN_HEAD)
205                         die("bug: a non-header pattern in grep header list.");
206                 if (p->field < 0 || GREP_HEADER_FIELD_MAX <= p->field)
207                         die("bug: unknown header field %d", p->field);
208                 compile_regexp(p, opt);
209         }
210         return header_expr;
213 void compile_grep_patterns(struct grep_opt *opt)
215         struct grep_pat *p;
216         struct grep_expr *header_expr = prep_header_patterns(opt);
218         for (p = opt->pattern_list; p; p = p->next) {
219                 switch (p->token) {
220                 case GREP_PATTERN: /* atom */
221                 case GREP_PATTERN_HEAD:
222                 case GREP_PATTERN_BODY:
223                         compile_regexp(p, opt);
224                         break;
225                 default:
226                         opt->extended = 1;
227                         break;
228                 }
229         }
231         if (opt->all_match || header_expr)
232                 opt->extended = 1;
233         else if (!opt->extended)
234                 return;
236         p = opt->pattern_list;
237         if (p)
238                 opt->pattern_expression = compile_pattern_expr(&p);
239         if (p)
240                 die("incomplete pattern expression: %s", p->pattern);
242         if (!header_expr)
243                 return;
245         if (opt->pattern_expression) {
246                 struct grep_expr *z;
247                 z = xcalloc(1, sizeof(*z));
248                 z->node = GREP_NODE_OR;
249                 z->u.binary.left = opt->pattern_expression;
250                 z->u.binary.right = header_expr;
251                 opt->pattern_expression = z;
252         } else {
253                 opt->pattern_expression = header_expr;
254         }
255         opt->all_match = 1;
258 static void free_pattern_expr(struct grep_expr *x)
260         switch (x->node) {
261         case GREP_NODE_ATOM:
262                 break;
263         case GREP_NODE_NOT:
264                 free_pattern_expr(x->u.unary);
265                 break;
266         case GREP_NODE_AND:
267         case GREP_NODE_OR:
268                 free_pattern_expr(x->u.binary.left);
269                 free_pattern_expr(x->u.binary.right);
270                 break;
271         }
272         free(x);
275 void free_grep_patterns(struct grep_opt *opt)
277         struct grep_pat *p, *n;
279         for (p = opt->pattern_list; p; p = n) {
280                 n = p->next;
281                 switch (p->token) {
282                 case GREP_PATTERN: /* atom */
283                 case GREP_PATTERN_HEAD:
284                 case GREP_PATTERN_BODY:
285                         regfree(&p->regexp);
286                         break;
287                 default:
288                         break;
289                 }
290                 free(p);
291         }
293         if (!opt->extended)
294                 return;
295         free_pattern_expr(opt->pattern_expression);
298 static char *end_of_line(char *cp, unsigned long *left)
300         unsigned long l = *left;
301         while (l && *cp != '\n') {
302                 l--;
303                 cp++;
304         }
305         *left = l;
306         return cp;
309 static int word_char(char ch)
311         return isalnum(ch) || ch == '_';
314 static void output_color(struct grep_opt *opt, const void *data, size_t size,
315                          const char *color)
317         if (opt->color && color && color[0]) {
318                 opt->output(opt, color, strlen(color));
319                 opt->output(opt, data, size);
320                 opt->output(opt, GIT_COLOR_RESET, strlen(GIT_COLOR_RESET));
321         } else
322                 opt->output(opt, data, size);
325 static void output_sep(struct grep_opt *opt, char sign)
327         if (opt->null_following_name)
328                 opt->output(opt, "\0", 1);
329         else
330                 output_color(opt, &sign, 1, opt->color_sep);
333 static void show_name(struct grep_opt *opt, const char *name)
335         output_color(opt, name, strlen(name), opt->color_filename);
336         opt->output(opt, opt->null_following_name ? "\0" : "\n", 1);
339 static int fixmatch(struct grep_pat *p, char *line, char *eol,
340                     regmatch_t *match)
342         char *hit;
344         if (p->ignore_case) {
345                 char *s = line;
346                 do {
347                         hit = strcasestr(s, p->pattern);
348                         if (hit)
349                                 break;
350                         s += strlen(s) + 1;
351                 } while (s < eol);
352         } else
353                 hit = memmem(line, eol - line, p->pattern, p->patternlen);
355         if (!hit) {
356                 match->rm_so = match->rm_eo = -1;
357                 return REG_NOMATCH;
358         }
359         else {
360                 match->rm_so = hit - line;
361                 match->rm_eo = match->rm_so + p->patternlen;
362                 return 0;
363         }
366 static int regmatch(const regex_t *preg, char *line, char *eol,
367                     regmatch_t *match, int eflags)
369 #ifdef REG_STARTEND
370         match->rm_so = 0;
371         match->rm_eo = eol - line;
372         eflags |= REG_STARTEND;
373 #endif
374         return regexec(preg, line, 1, match, eflags);
377 static int strip_timestamp(char *bol, char **eol_p)
379         char *eol = *eol_p;
380         int ch;
382         while (bol < --eol) {
383                 if (*eol != '>')
384                         continue;
385                 *eol_p = ++eol;
386                 ch = *eol;
387                 *eol = '\0';
388                 return ch;
389         }
390         return 0;
393 static struct {
394         const char *field;
395         size_t len;
396 } header_field[] = {
397         { "author ", 7 },
398         { "committer ", 10 },
399 };
401 static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
402                              enum grep_context ctx,
403                              regmatch_t *pmatch, int eflags)
405         int hit = 0;
406         int saved_ch = 0;
407         const char *start = bol;
409         if ((p->token != GREP_PATTERN) &&
410             ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
411                 return 0;
413         if (p->token == GREP_PATTERN_HEAD) {
414                 const char *field;
415                 size_t len;
416                 assert(p->field < ARRAY_SIZE(header_field));
417                 field = header_field[p->field].field;
418                 len = header_field[p->field].len;
419                 if (strncmp(bol, field, len))
420                         return 0;
421                 bol += len;
422                 saved_ch = strip_timestamp(bol, &eol);
423         }
425  again:
426         if (p->fixed)
427                 hit = !fixmatch(p, bol, eol, pmatch);
428         else
429                 hit = !regmatch(&p->regexp, bol, eol, pmatch, eflags);
431         if (hit && p->word_regexp) {
432                 if ((pmatch[0].rm_so < 0) ||
433                     (eol - bol) < pmatch[0].rm_so ||
434                     (pmatch[0].rm_eo < 0) ||
435                     (eol - bol) < pmatch[0].rm_eo)
436                         die("regexp returned nonsense");
438                 /* Match beginning must be either beginning of the
439                  * line, or at word boundary (i.e. the last char must
440                  * not be a word char).  Similarly, match end must be
441                  * either end of the line, or at word boundary
442                  * (i.e. the next char must not be a word char).
443                  */
444                 if ( ((pmatch[0].rm_so == 0) ||
445                       !word_char(bol[pmatch[0].rm_so-1])) &&
446                      ((pmatch[0].rm_eo == (eol-bol)) ||
447                       !word_char(bol[pmatch[0].rm_eo])) )
448                         ;
449                 else
450                         hit = 0;
452                 /* Words consist of at least one character. */
453                 if (pmatch->rm_so == pmatch->rm_eo)
454                         hit = 0;
456                 if (!hit && pmatch[0].rm_so + bol + 1 < eol) {
457                         /* There could be more than one match on the
458                          * line, and the first match might not be
459                          * strict word match.  But later ones could be!
460                          * Forward to the next possible start, i.e. the
461                          * next position following a non-word char.
462                          */
463                         bol = pmatch[0].rm_so + bol + 1;
464                         while (word_char(bol[-1]) && bol < eol)
465                                 bol++;
466                         eflags |= REG_NOTBOL;
467                         if (bol < eol)
468                                 goto again;
469                 }
470         }
471         if (p->token == GREP_PATTERN_HEAD && saved_ch)
472                 *eol = saved_ch;
473         if (hit) {
474                 pmatch[0].rm_so += bol - start;
475                 pmatch[0].rm_eo += bol - start;
476         }
477         return hit;
480 static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
481                            enum grep_context ctx, int collect_hits)
483         int h = 0;
484         regmatch_t match;
486         if (!x)
487                 die("Not a valid grep expression");
488         switch (x->node) {
489         case GREP_NODE_ATOM:
490                 h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
491                 break;
492         case GREP_NODE_NOT:
493                 h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0);
494                 break;
495         case GREP_NODE_AND:
496                 if (!match_expr_eval(x->u.binary.left, bol, eol, ctx, 0))
497                         return 0;
498                 h = match_expr_eval(x->u.binary.right, bol, eol, ctx, 0);
499                 break;
500         case GREP_NODE_OR:
501                 if (!collect_hits)
502                         return (match_expr_eval(x->u.binary.left,
503                                                 bol, eol, ctx, 0) ||
504                                 match_expr_eval(x->u.binary.right,
505                                                 bol, eol, ctx, 0));
506                 h = match_expr_eval(x->u.binary.left, bol, eol, ctx, 0);
507                 x->u.binary.left->hit |= h;
508                 h |= match_expr_eval(x->u.binary.right, bol, eol, ctx, 1);
509                 break;
510         default:
511                 die("Unexpected node type (internal error) %d", x->node);
512         }
513         if (collect_hits)
514                 x->hit |= h;
515         return h;
518 static int match_expr(struct grep_opt *opt, char *bol, char *eol,
519                       enum grep_context ctx, int collect_hits)
521         struct grep_expr *x = opt->pattern_expression;
522         return match_expr_eval(x, bol, eol, ctx, collect_hits);
525 static int match_line(struct grep_opt *opt, char *bol, char *eol,
526                       enum grep_context ctx, int collect_hits)
528         struct grep_pat *p;
529         regmatch_t match;
531         if (opt->extended)
532                 return match_expr(opt, bol, eol, ctx, collect_hits);
534         /* we do not call with collect_hits without being extended */
535         for (p = opt->pattern_list; p; p = p->next) {
536                 if (match_one_pattern(p, bol, eol, ctx, &match, 0))
537                         return 1;
538         }
539         return 0;
542 static int match_next_pattern(struct grep_pat *p, char *bol, char *eol,
543                               enum grep_context ctx,
544                               regmatch_t *pmatch, int eflags)
546         regmatch_t match;
548         if (!match_one_pattern(p, bol, eol, ctx, &match, eflags))
549                 return 0;
550         if (match.rm_so < 0 || match.rm_eo < 0)
551                 return 0;
552         if (pmatch->rm_so >= 0 && pmatch->rm_eo >= 0) {
553                 if (match.rm_so > pmatch->rm_so)
554                         return 1;
555                 if (match.rm_so == pmatch->rm_so && match.rm_eo < pmatch->rm_eo)
556                         return 1;
557         }
558         pmatch->rm_so = match.rm_so;
559         pmatch->rm_eo = match.rm_eo;
560         return 1;
563 static int next_match(struct grep_opt *opt, char *bol, char *eol,
564                       enum grep_context ctx, regmatch_t *pmatch, int eflags)
566         struct grep_pat *p;
567         int hit = 0;
569         pmatch->rm_so = pmatch->rm_eo = -1;
570         if (bol < eol) {
571                 for (p = opt->pattern_list; p; p = p->next) {
572                         switch (p->token) {
573                         case GREP_PATTERN: /* atom */
574                         case GREP_PATTERN_HEAD:
575                         case GREP_PATTERN_BODY:
576                                 hit |= match_next_pattern(p, bol, eol, ctx,
577                                                           pmatch, eflags);
578                                 break;
579                         default:
580                                 break;
581                         }
582                 }
583         }
584         return hit;
587 static void show_line(struct grep_opt *opt, char *bol, char *eol,
588                       const char *name, unsigned lno, char sign)
590         int rest = eol - bol;
591         char *line_color = NULL;
593         if (opt->pre_context || opt->post_context) {
594                 if (opt->last_shown == 0) {
595                         if (opt->show_hunk_mark) {
596                                 output_color(opt, "--", 2, opt->color_sep);
597                                 opt->output(opt, "\n", 1);
598                         }
599                 } else if (lno > opt->last_shown + 1) {
600                         output_color(opt, "--", 2, opt->color_sep);
601                         opt->output(opt, "\n", 1);
602                 }
603         }
604         opt->last_shown = lno;
606         if (opt->pathname) {
607                 output_color(opt, name, strlen(name), opt->color_filename);
608                 output_sep(opt, sign);
609         }
610         if (opt->linenum) {
611                 char buf[32];
612                 snprintf(buf, sizeof(buf), "%d", lno);
613                 output_color(opt, buf, strlen(buf), opt->color_lineno);
614                 output_sep(opt, sign);
615         }
616         if (opt->color) {
617                 regmatch_t match;
618                 enum grep_context ctx = GREP_CONTEXT_BODY;
619                 int ch = *eol;
620                 int eflags = 0;
622                 if (sign == ':')
623                         line_color = opt->color_selected;
624                 else if (sign == '-')
625                         line_color = opt->color_context;
626                 else if (sign == '=')
627                         line_color = opt->color_function;
628                 *eol = '\0';
629                 while (next_match(opt, bol, eol, ctx, &match, eflags)) {
630                         if (match.rm_so == match.rm_eo)
631                                 break;
633                         output_color(opt, bol, match.rm_so, line_color);
634                         output_color(opt, bol + match.rm_so,
635                                      match.rm_eo - match.rm_so,
636                                      opt->color_match);
637                         bol += match.rm_eo;
638                         rest -= match.rm_eo;
639                         eflags = REG_NOTBOL;
640                 }
641                 *eol = ch;
642         }
643         output_color(opt, bol, rest, line_color);
644         opt->output(opt, "\n", 1);
647 static int match_funcname(struct grep_opt *opt, char *bol, char *eol)
649         xdemitconf_t *xecfg = opt->priv;
650         if (xecfg && xecfg->find_func) {
651                 char buf[1];
652                 return xecfg->find_func(bol, eol - bol, buf, 1,
653                                         xecfg->find_func_priv) >= 0;
654         }
656         if (bol == eol)
657                 return 0;
658         if (isalpha(*bol) || *bol == '_' || *bol == '$')
659                 return 1;
660         return 0;
663 static void show_funcname_line(struct grep_opt *opt, const char *name,
664                                char *buf, char *bol, unsigned lno)
666         while (bol > buf) {
667                 char *eol = --bol;
669                 while (bol > buf && bol[-1] != '\n')
670                         bol--;
671                 lno--;
673                 if (lno <= opt->last_shown)
674                         break;
676                 if (match_funcname(opt, bol, eol)) {
677                         show_line(opt, bol, eol, name, lno, '=');
678                         break;
679                 }
680         }
683 static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
684                              char *bol, unsigned lno)
686         unsigned cur = lno, from = 1, funcname_lno = 0;
687         int funcname_needed = opt->funcname;
689         if (opt->pre_context < lno)
690                 from = lno - opt->pre_context;
691         if (from <= opt->last_shown)
692                 from = opt->last_shown + 1;
694         /* Rewind. */
695         while (bol > buf && cur > from) {
696                 char *eol = --bol;
698                 while (bol > buf && bol[-1] != '\n')
699                         bol--;
700                 cur--;
701                 if (funcname_needed && match_funcname(opt, bol, eol)) {
702                         funcname_lno = cur;
703                         funcname_needed = 0;
704                 }
705         }
707         /* We need to look even further back to find a function signature. */
708         if (opt->funcname && funcname_needed)
709                 show_funcname_line(opt, name, buf, bol, cur);
711         /* Back forward. */
712         while (cur < lno) {
713                 char *eol = bol, sign = (cur == funcname_lno) ? '=' : '-';
715                 while (*eol != '\n')
716                         eol++;
717                 show_line(opt, bol, eol, name, cur, sign);
718                 bol = eol + 1;
719                 cur++;
720         }
723 static int should_lookahead(struct grep_opt *opt)
725         struct grep_pat *p;
727         if (opt->extended)
728                 return 0; /* punt for too complex stuff */
729         if (opt->invert)
730                 return 0;
731         for (p = opt->pattern_list; p; p = p->next) {
732                 if (p->token != GREP_PATTERN)
733                         return 0; /* punt for "header only" and stuff */
734         }
735         return 1;
738 static int look_ahead(struct grep_opt *opt,
739                       unsigned long *left_p,
740                       unsigned *lno_p,
741                       char **bol_p)
743         unsigned lno = *lno_p;
744         char *bol = *bol_p;
745         struct grep_pat *p;
746         char *sp, *last_bol;
747         regoff_t earliest = -1;
749         for (p = opt->pattern_list; p; p = p->next) {
750                 int hit;
751                 regmatch_t m;
753                 if (p->fixed)
754                         hit = !fixmatch(p, bol, bol + *left_p, &m);
755                 else
756                         hit = !regmatch(&p->regexp, bol, bol + *left_p, &m, 0);
757                 if (!hit || m.rm_so < 0 || m.rm_eo < 0)
758                         continue;
759                 if (earliest < 0 || m.rm_so < earliest)
760                         earliest = m.rm_so;
761         }
763         if (earliest < 0) {
764                 *bol_p = bol + *left_p;
765                 *left_p = 0;
766                 return 1;
767         }
768         for (sp = bol + earliest; bol < sp && sp[-1] != '\n'; sp--)
769                 ; /* find the beginning of the line */
770         last_bol = sp;
772         for (sp = bol; sp < last_bol; sp++) {
773                 if (*sp == '\n')
774                         lno++;
775         }
776         *left_p -= last_bol - bol;
777         *bol_p = last_bol;
778         *lno_p = lno;
779         return 0;
782 int grep_threads_ok(const struct grep_opt *opt)
784         /* If this condition is true, then we may use the attribute
785          * machinery in grep_buffer_1. The attribute code is not
786          * thread safe, so we disable the use of threads.
787          */
788         if (opt->funcname && !opt->unmatch_name_only && !opt->status_only &&
789             !opt->name_only)
790                 return 0;
792         return 1;
795 static void std_output(struct grep_opt *opt, const void *buf, size_t size)
797         fwrite(buf, size, 1, stdout);
800 static int grep_buffer_1(struct grep_opt *opt, const char *name,
801                          char *buf, unsigned long size, int collect_hits)
803         char *bol = buf;
804         unsigned long left = size;
805         unsigned lno = 1;
806         unsigned last_hit = 0;
807         int binary_match_only = 0;
808         unsigned count = 0;
809         int try_lookahead = 0;
810         enum grep_context ctx = GREP_CONTEXT_HEAD;
811         xdemitconf_t xecfg;
813         if (!opt->output)
814                 opt->output = std_output;
816         if (opt->last_shown && (opt->pre_context || opt->post_context) &&
817             opt->output == std_output)
818                 opt->show_hunk_mark = 1;
819         opt->last_shown = 0;
821         switch (opt->binary) {
822         case GREP_BINARY_DEFAULT:
823                 if (buffer_is_binary(buf, size))
824                         binary_match_only = 1;
825                 break;
826         case GREP_BINARY_NOMATCH:
827                 if (buffer_is_binary(buf, size))
828                         return 0; /* Assume unmatch */
829                 break;
830         case GREP_BINARY_TEXT:
831                 break;
832         default:
833                 die("bug: unknown binary handling mode");
834         }
836         memset(&xecfg, 0, sizeof(xecfg));
837         if (opt->funcname && !opt->unmatch_name_only && !opt->status_only &&
838             !opt->name_only && !binary_match_only && !collect_hits) {
839                 struct userdiff_driver *drv = userdiff_find_by_path(name);
840                 if (drv && drv->funcname.pattern) {
841                         const struct userdiff_funcname *pe = &drv->funcname;
842                         xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
843                         opt->priv = &xecfg;
844                 }
845         }
846         try_lookahead = should_lookahead(opt);
848         while (left) {
849                 char *eol, ch;
850                 int hit;
852                 /*
853                  * look_ahead() skips quicly to the line that possibly
854                  * has the next hit; don't call it if we need to do
855                  * something more than just skipping the current line
856                  * in response to an unmatch for the current line.  E.g.
857                  * inside a post-context window, we will show the current
858                  * line as a context around the previous hit when it
859                  * doesn't hit.
860                  */
861                 if (try_lookahead
862                     && !(last_hit
863                          && lno <= last_hit + opt->post_context)
864                     && look_ahead(opt, &left, &lno, &bol))
865                         break;
866                 eol = end_of_line(bol, &left);
867                 ch = *eol;
868                 *eol = 0;
870                 if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol))
871                         ctx = GREP_CONTEXT_BODY;
873                 hit = match_line(opt, bol, eol, ctx, collect_hits);
874                 *eol = ch;
876                 if (collect_hits)
877                         goto next_line;
879                 /* "grep -v -e foo -e bla" should list lines
880                  * that do not have either, so inversion should
881                  * be done outside.
882                  */
883                 if (opt->invert)
884                         hit = !hit;
885                 if (opt->unmatch_name_only) {
886                         if (hit)
887                                 return 0;
888                         goto next_line;
889                 }
890                 if (hit) {
891                         count++;
892                         if (opt->status_only)
893                                 return 1;
894                         if (opt->name_only) {
895                                 show_name(opt, name);
896                                 return 1;
897                         }
898                         if (opt->count)
899                                 goto next_line;
900                         if (binary_match_only) {
901                                 opt->output(opt, "Binary file ", 12);
902                                 output_color(opt, name, strlen(name),
903                                              opt->color_filename);
904                                 opt->output(opt, " matches\n", 9);
905                                 return 1;
906                         }
907                         /* Hit at this line.  If we haven't shown the
908                          * pre-context lines, we would need to show them.
909                          */
910                         if (opt->pre_context)
911                                 show_pre_context(opt, name, buf, bol, lno);
912                         else if (opt->funcname)
913                                 show_funcname_line(opt, name, buf, bol, lno);
914                         show_line(opt, bol, eol, name, lno, ':');
915                         last_hit = lno;
916                 }
917                 else if (last_hit &&
918                          lno <= last_hit + opt->post_context) {
919                         /* If the last hit is within the post context,
920                          * we need to show this line.
921                          */
922                         show_line(opt, bol, eol, name, lno, '-');
923                 }
925         next_line:
926                 bol = eol + 1;
927                 if (!left)
928                         break;
929                 left--;
930                 lno++;
931         }
933         if (collect_hits)
934                 return 0;
936         if (opt->status_only)
937                 return 0;
938         if (opt->unmatch_name_only) {
939                 /* We did not see any hit, so we want to show this */
940                 show_name(opt, name);
941                 return 1;
942         }
944         xdiff_clear_find_func(&xecfg);
945         opt->priv = NULL;
947         /* NEEDSWORK:
948          * The real "grep -c foo *.c" gives many "bar.c:0" lines,
949          * which feels mostly useless but sometimes useful.  Maybe
950          * make it another option?  For now suppress them.
951          */
952         if (opt->count && count) {
953                 char buf[32];
954                 output_color(opt, name, strlen(name), opt->color_filename);
955                 output_sep(opt, ':');
956                 snprintf(buf, sizeof(buf), "%u\n", count);
957                 opt->output(opt, buf, strlen(buf));
958                 return 1;
959         }
960         return !!last_hit;
963 static void clr_hit_marker(struct grep_expr *x)
965         /* All-hit markers are meaningful only at the very top level
966          * OR node.
967          */
968         while (1) {
969                 x->hit = 0;
970                 if (x->node != GREP_NODE_OR)
971                         return;
972                 x->u.binary.left->hit = 0;
973                 x = x->u.binary.right;
974         }
977 static int chk_hit_marker(struct grep_expr *x)
979         /* Top level nodes have hit markers.  See if they all are hits */
980         while (1) {
981                 if (x->node != GREP_NODE_OR)
982                         return x->hit;
983                 if (!x->u.binary.left->hit)
984                         return 0;
985                 x = x->u.binary.right;
986         }
989 int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size)
991         /*
992          * we do not have to do the two-pass grep when we do not check
993          * buffer-wide "all-match".
994          */
995         if (!opt->all_match)
996                 return grep_buffer_1(opt, name, buf, size, 0);
998         /* Otherwise the toplevel "or" terms hit a bit differently.
999          * We first clear hit markers from them.
1000          */
1001         clr_hit_marker(opt->pattern_expression);
1002         grep_buffer_1(opt, name, buf, size, 1);
1004         if (!chk_hit_marker(opt->pattern_expression))
1005                 return 0;
1007         return grep_buffer_1(opt, name, buf, size, 0);