Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 1 | #include "cache.h" |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 2 | #include "grep.h" |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 3 | #include "userdiff.h" |
Johannes Schindelin | 6bfce93 | 2007-06-05 03:36:11 +0100 | [diff] [blame] | 4 | #include "xdiff-interface.h" |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 5 | |
Junio C Hamano | a4d7d2c | 2008-09-04 22:15:02 -0700 | [diff] [blame] | 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->origin = "header"; |
| 11 | p->no = 0; |
| 12 | p->token = GREP_PATTERN_HEAD; |
| 13 | p->field = field; |
| 14 | *opt->pattern_tail = p; |
| 15 | opt->pattern_tail = &p->next; |
| 16 | p->next = NULL; |
| 17 | } |
| 18 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 19 | void append_grep_pattern(struct grep_opt *opt, const char *pat, |
| 20 | const char *origin, int no, enum grep_pat_token t) |
| 21 | { |
| 22 | struct grep_pat *p = xcalloc(1, sizeof(*p)); |
| 23 | p->pattern = pat; |
| 24 | p->origin = origin; |
| 25 | p->no = no; |
| 26 | p->token = t; |
| 27 | *opt->pattern_tail = p; |
| 28 | opt->pattern_tail = &p->next; |
| 29 | p->next = NULL; |
| 30 | } |
| 31 | |
René Scharfe | c822255 | 2009-01-10 00:18:34 +0100 | [diff] [blame] | 32 | static int is_fixed(const char *s) |
| 33 | { |
René Scharfe | f9b7cce | 2009-01-17 16:50:37 +0100 | [diff] [blame] | 34 | while (*s && !is_regex_special(*s)) |
René Scharfe | c822255 | 2009-01-10 00:18:34 +0100 | [diff] [blame] | 35 | s++; |
| 36 | return !*s; |
| 37 | } |
| 38 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 39 | static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) |
| 40 | { |
René Scharfe | c822255 | 2009-01-10 00:18:34 +0100 | [diff] [blame] | 41 | int err; |
| 42 | |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 43 | p->word_regexp = opt->word_regexp; |
| 44 | |
René Scharfe | c822255 | 2009-01-10 00:18:34 +0100 | [diff] [blame] | 45 | if (opt->fixed || is_fixed(p->pattern)) |
| 46 | p->fixed = 1; |
| 47 | if (opt->regflags & REG_ICASE) |
| 48 | p->fixed = 0; |
| 49 | if (p->fixed) |
| 50 | return; |
| 51 | |
| 52 | err = regcomp(&p->regexp, p->pattern, opt->regflags); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 53 | if (err) { |
| 54 | char errbuf[1024]; |
| 55 | char where[1024]; |
| 56 | if (p->no) |
| 57 | sprintf(where, "In '%s' at %d, ", |
| 58 | p->origin, p->no); |
| 59 | else if (p->origin) |
| 60 | sprintf(where, "%s, ", p->origin); |
| 61 | else |
| 62 | where[0] = 0; |
| 63 | regerror(err, &p->regexp, errbuf, 1024); |
| 64 | regfree(&p->regexp); |
| 65 | die("%s'%s': %s", where, p->pattern, errbuf); |
| 66 | } |
| 67 | } |
| 68 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 69 | static struct grep_expr *compile_pattern_or(struct grep_pat **); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 70 | static struct grep_expr *compile_pattern_atom(struct grep_pat **list) |
| 71 | { |
| 72 | struct grep_pat *p; |
| 73 | struct grep_expr *x; |
| 74 | |
| 75 | p = *list; |
Linus Torvalds | c922b01 | 2009-04-27 11:10:24 -0700 | [diff] [blame] | 76 | if (!p) |
| 77 | return NULL; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 78 | switch (p->token) { |
| 79 | case GREP_PATTERN: /* atom */ |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 80 | case GREP_PATTERN_HEAD: |
| 81 | case GREP_PATTERN_BODY: |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 82 | x = xcalloc(1, sizeof (struct grep_expr)); |
| 83 | x->node = GREP_NODE_ATOM; |
| 84 | x->u.atom = p; |
| 85 | *list = p->next; |
| 86 | return x; |
| 87 | case GREP_OPEN_PAREN: |
| 88 | *list = p->next; |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 89 | x = compile_pattern_or(list); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 90 | if (!*list || (*list)->token != GREP_CLOSE_PAREN) |
| 91 | die("unmatched parenthesis"); |
| 92 | *list = (*list)->next; |
| 93 | return x; |
| 94 | default: |
| 95 | return NULL; |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | static struct grep_expr *compile_pattern_not(struct grep_pat **list) |
| 100 | { |
| 101 | struct grep_pat *p; |
| 102 | struct grep_expr *x; |
| 103 | |
| 104 | p = *list; |
Linus Torvalds | c922b01 | 2009-04-27 11:10:24 -0700 | [diff] [blame] | 105 | if (!p) |
| 106 | return NULL; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 107 | switch (p->token) { |
| 108 | case GREP_NOT: |
| 109 | if (!p->next) |
| 110 | die("--not not followed by pattern expression"); |
| 111 | *list = p->next; |
| 112 | x = xcalloc(1, sizeof (struct grep_expr)); |
| 113 | x->node = GREP_NODE_NOT; |
| 114 | x->u.unary = compile_pattern_not(list); |
| 115 | if (!x->u.unary) |
| 116 | die("--not followed by non pattern expression"); |
| 117 | return x; |
| 118 | default: |
| 119 | return compile_pattern_atom(list); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | static struct grep_expr *compile_pattern_and(struct grep_pat **list) |
| 124 | { |
| 125 | struct grep_pat *p; |
| 126 | struct grep_expr *x, *y, *z; |
| 127 | |
| 128 | x = compile_pattern_not(list); |
| 129 | p = *list; |
| 130 | if (p && p->token == GREP_AND) { |
| 131 | if (!p->next) |
| 132 | die("--and not followed by pattern expression"); |
| 133 | *list = p->next; |
| 134 | y = compile_pattern_and(list); |
| 135 | if (!y) |
| 136 | die("--and not followed by pattern expression"); |
| 137 | z = xcalloc(1, sizeof (struct grep_expr)); |
| 138 | z->node = GREP_NODE_AND; |
| 139 | z->u.binary.left = x; |
| 140 | z->u.binary.right = y; |
| 141 | return z; |
| 142 | } |
| 143 | return x; |
| 144 | } |
| 145 | |
| 146 | static struct grep_expr *compile_pattern_or(struct grep_pat **list) |
| 147 | { |
| 148 | struct grep_pat *p; |
| 149 | struct grep_expr *x, *y, *z; |
| 150 | |
| 151 | x = compile_pattern_and(list); |
| 152 | p = *list; |
| 153 | if (x && p && p->token != GREP_CLOSE_PAREN) { |
| 154 | y = compile_pattern_or(list); |
| 155 | if (!y) |
| 156 | die("not a pattern expression %s", p->pattern); |
| 157 | z = xcalloc(1, sizeof (struct grep_expr)); |
| 158 | z->node = GREP_NODE_OR; |
| 159 | z->u.binary.left = x; |
| 160 | z->u.binary.right = y; |
| 161 | return z; |
| 162 | } |
| 163 | return x; |
| 164 | } |
| 165 | |
| 166 | static struct grep_expr *compile_pattern_expr(struct grep_pat **list) |
| 167 | { |
| 168 | return compile_pattern_or(list); |
| 169 | } |
| 170 | |
| 171 | void compile_grep_patterns(struct grep_opt *opt) |
| 172 | { |
| 173 | struct grep_pat *p; |
| 174 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 175 | if (opt->all_match) |
| 176 | opt->extended = 1; |
| 177 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 178 | for (p = opt->pattern_list; p; p = p->next) { |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 179 | switch (p->token) { |
| 180 | case GREP_PATTERN: /* atom */ |
| 181 | case GREP_PATTERN_HEAD: |
| 182 | case GREP_PATTERN_BODY: |
René Scharfe | c822255 | 2009-01-10 00:18:34 +0100 | [diff] [blame] | 183 | compile_regexp(p, opt); |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 184 | break; |
| 185 | default: |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 186 | opt->extended = 1; |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 187 | break; |
| 188 | } |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | if (!opt->extended) |
| 192 | return; |
| 193 | |
| 194 | /* Then bundle them up in an expression. |
| 195 | * A classic recursive descent parser would do. |
| 196 | */ |
| 197 | p = opt->pattern_list; |
Michele Ballabio | ba150a3 | 2009-03-18 21:53:27 +0100 | [diff] [blame] | 198 | if (p) |
| 199 | opt->pattern_expression = compile_pattern_expr(&p); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 200 | if (p) |
| 201 | die("incomplete pattern expression: %s", p->pattern); |
| 202 | } |
| 203 | |
Junio C Hamano | b48fb5b | 2006-09-27 16:27:10 -0700 | [diff] [blame] | 204 | static void free_pattern_expr(struct grep_expr *x) |
| 205 | { |
| 206 | switch (x->node) { |
| 207 | case GREP_NODE_ATOM: |
| 208 | break; |
| 209 | case GREP_NODE_NOT: |
| 210 | free_pattern_expr(x->u.unary); |
| 211 | break; |
| 212 | case GREP_NODE_AND: |
| 213 | case GREP_NODE_OR: |
| 214 | free_pattern_expr(x->u.binary.left); |
| 215 | free_pattern_expr(x->u.binary.right); |
| 216 | break; |
| 217 | } |
| 218 | free(x); |
| 219 | } |
| 220 | |
| 221 | void free_grep_patterns(struct grep_opt *opt) |
| 222 | { |
| 223 | struct grep_pat *p, *n; |
| 224 | |
| 225 | for (p = opt->pattern_list; p; p = n) { |
| 226 | n = p->next; |
| 227 | switch (p->token) { |
| 228 | case GREP_PATTERN: /* atom */ |
| 229 | case GREP_PATTERN_HEAD: |
| 230 | case GREP_PATTERN_BODY: |
| 231 | regfree(&p->regexp); |
| 232 | break; |
| 233 | default: |
| 234 | break; |
| 235 | } |
| 236 | free(p); |
| 237 | } |
| 238 | |
| 239 | if (!opt->extended) |
| 240 | return; |
| 241 | free_pattern_expr(opt->pattern_expression); |
| 242 | } |
| 243 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 244 | static char *end_of_line(char *cp, unsigned long *left) |
| 245 | { |
| 246 | unsigned long l = *left; |
| 247 | while (l && *cp != '\n') { |
| 248 | l--; |
| 249 | cp++; |
| 250 | } |
| 251 | *left = l; |
| 252 | return cp; |
| 253 | } |
| 254 | |
| 255 | static int word_char(char ch) |
| 256 | { |
| 257 | return isalnum(ch) || ch == '_'; |
| 258 | } |
| 259 | |
Raphael Zimmerer | 83caecc | 2008-10-01 18:11:15 +0200 | [diff] [blame] | 260 | static void show_name(struct grep_opt *opt, const char *name) |
| 261 | { |
| 262 | printf("%s%c", name, opt->null_following_name ? '\0' : '\n'); |
| 263 | } |
| 264 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 265 | static int fixmatch(const char *pattern, char *line, regmatch_t *match) |
| 266 | { |
| 267 | char *hit = strstr(line, pattern); |
| 268 | if (!hit) { |
| 269 | match->rm_so = match->rm_eo = -1; |
| 270 | return REG_NOMATCH; |
| 271 | } |
| 272 | else { |
| 273 | match->rm_so = hit - line; |
| 274 | match->rm_eo = match->rm_so + strlen(pattern); |
| 275 | return 0; |
| 276 | } |
| 277 | } |
| 278 | |
Junio C Hamano | a4d7d2c | 2008-09-04 22:15:02 -0700 | [diff] [blame] | 279 | static int strip_timestamp(char *bol, char **eol_p) |
| 280 | { |
| 281 | char *eol = *eol_p; |
| 282 | int ch; |
| 283 | |
| 284 | while (bol < --eol) { |
| 285 | if (*eol != '>') |
| 286 | continue; |
| 287 | *eol_p = ++eol; |
| 288 | ch = *eol; |
| 289 | *eol = '\0'; |
| 290 | return ch; |
| 291 | } |
| 292 | return 0; |
| 293 | } |
| 294 | |
| 295 | static struct { |
| 296 | const char *field; |
| 297 | size_t len; |
| 298 | } header_field[] = { |
| 299 | { "author ", 7 }, |
| 300 | { "committer ", 10 }, |
| 301 | }; |
| 302 | |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 303 | static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 304 | enum grep_context ctx, |
| 305 | regmatch_t *pmatch, int eflags) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 306 | { |
| 307 | int hit = 0; |
Junio C Hamano | a4d7d2c | 2008-09-04 22:15:02 -0700 | [diff] [blame] | 308 | int saved_ch = 0; |
René Scharfe | e701fad | 2009-05-20 23:31:53 +0200 | [diff] [blame] | 309 | const char *start = bol; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 310 | |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 311 | if ((p->token != GREP_PATTERN) && |
| 312 | ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD))) |
| 313 | return 0; |
| 314 | |
Junio C Hamano | a4d7d2c | 2008-09-04 22:15:02 -0700 | [diff] [blame] | 315 | if (p->token == GREP_PATTERN_HEAD) { |
| 316 | const char *field; |
| 317 | size_t len; |
| 318 | assert(p->field < ARRAY_SIZE(header_field)); |
| 319 | field = header_field[p->field].field; |
| 320 | len = header_field[p->field].len; |
| 321 | if (strncmp(bol, field, len)) |
| 322 | return 0; |
| 323 | bol += len; |
| 324 | saved_ch = strip_timestamp(bol, &eol); |
| 325 | } |
| 326 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 327 | again: |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 328 | if (p->fixed) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 329 | hit = !fixmatch(p->pattern, bol, pmatch); |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 330 | else |
| 331 | hit = !regexec(&p->regexp, bol, 1, pmatch, eflags); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 332 | |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 333 | if (hit && p->word_regexp) { |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 334 | if ((pmatch[0].rm_so < 0) || |
René Scharfe | 84201ea | 2009-06-03 18:19:01 +0200 | [diff] [blame] | 335 | (eol - bol) < pmatch[0].rm_so || |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 336 | (pmatch[0].rm_eo < 0) || |
| 337 | (eol - bol) < pmatch[0].rm_eo) |
| 338 | die("regexp returned nonsense"); |
| 339 | |
| 340 | /* Match beginning must be either beginning of the |
| 341 | * line, or at word boundary (i.e. the last char must |
| 342 | * not be a word char). Similarly, match end must be |
| 343 | * either end of the line, or at word boundary |
| 344 | * (i.e. the next char must not be a word char). |
| 345 | */ |
René Scharfe | fb62eb7 | 2009-01-10 00:08:40 +0100 | [diff] [blame] | 346 | if ( ((pmatch[0].rm_so == 0) || |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 347 | !word_char(bol[pmatch[0].rm_so-1])) && |
| 348 | ((pmatch[0].rm_eo == (eol-bol)) || |
| 349 | !word_char(bol[pmatch[0].rm_eo])) ) |
| 350 | ; |
| 351 | else |
| 352 | hit = 0; |
| 353 | |
René Scharfe | 84201ea | 2009-06-03 18:19:01 +0200 | [diff] [blame] | 354 | /* Words consist of at least one character. */ |
| 355 | if (pmatch->rm_so == pmatch->rm_eo) |
| 356 | hit = 0; |
| 357 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 358 | if (!hit && pmatch[0].rm_so + bol + 1 < eol) { |
| 359 | /* There could be more than one match on the |
| 360 | * line, and the first match might not be |
| 361 | * strict word match. But later ones could be! |
René Scharfe | fb62eb7 | 2009-01-10 00:08:40 +0100 | [diff] [blame] | 362 | * Forward to the next possible start, i.e. the |
| 363 | * next position following a non-word char. |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 364 | */ |
| 365 | bol = pmatch[0].rm_so + bol + 1; |
René Scharfe | fb62eb7 | 2009-01-10 00:08:40 +0100 | [diff] [blame] | 366 | while (word_char(bol[-1]) && bol < eol) |
| 367 | bol++; |
René Scharfe | dbb6a4a | 2009-05-23 13:45:26 +0200 | [diff] [blame] | 368 | eflags |= REG_NOTBOL; |
René Scharfe | fb62eb7 | 2009-01-10 00:08:40 +0100 | [diff] [blame] | 369 | if (bol < eol) |
| 370 | goto again; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 371 | } |
| 372 | } |
Junio C Hamano | a4d7d2c | 2008-09-04 22:15:02 -0700 | [diff] [blame] | 373 | if (p->token == GREP_PATTERN_HEAD && saved_ch) |
| 374 | *eol = saved_ch; |
René Scharfe | e701fad | 2009-05-20 23:31:53 +0200 | [diff] [blame] | 375 | if (hit) { |
| 376 | pmatch[0].rm_so += bol - start; |
| 377 | pmatch[0].rm_eo += bol - start; |
| 378 | } |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 379 | return hit; |
| 380 | } |
| 381 | |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 382 | static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, |
| 383 | enum grep_context ctx, int collect_hits) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 384 | { |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 385 | int h = 0; |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 386 | regmatch_t match; |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 387 | |
Linus Torvalds | c922b01 | 2009-04-27 11:10:24 -0700 | [diff] [blame] | 388 | if (!x) |
| 389 | die("Not a valid grep expression"); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 390 | switch (x->node) { |
| 391 | case GREP_NODE_ATOM: |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 392 | h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 393 | break; |
| 394 | case GREP_NODE_NOT: |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 395 | h = !match_expr_eval(x->u.unary, bol, eol, ctx, 0); |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 396 | break; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 397 | case GREP_NODE_AND: |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 398 | if (!match_expr_eval(x->u.binary.left, bol, eol, ctx, 0)) |
René Scharfe | 252d560 | 2009-03-07 13:27:15 +0100 | [diff] [blame] | 399 | return 0; |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 400 | h = match_expr_eval(x->u.binary.right, bol, eol, ctx, 0); |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 401 | break; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 402 | case GREP_NODE_OR: |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 403 | if (!collect_hits) |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 404 | return (match_expr_eval(x->u.binary.left, |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 405 | bol, eol, ctx, 0) || |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 406 | match_expr_eval(x->u.binary.right, |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 407 | bol, eol, ctx, 0)); |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 408 | h = match_expr_eval(x->u.binary.left, bol, eol, ctx, 0); |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 409 | x->u.binary.left->hit |= h; |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 410 | h |= match_expr_eval(x->u.binary.right, bol, eol, ctx, 1); |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 411 | break; |
| 412 | default: |
Alexander Potashev | d753070 | 2009-01-04 21:38:41 +0300 | [diff] [blame] | 413 | die("Unexpected node type (internal error) %d", x->node); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 414 | } |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 415 | if (collect_hits) |
| 416 | x->hit |= h; |
| 417 | return h; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 418 | } |
| 419 | |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 420 | static int match_expr(struct grep_opt *opt, char *bol, char *eol, |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 421 | enum grep_context ctx, int collect_hits) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 422 | { |
| 423 | struct grep_expr *x = opt->pattern_expression; |
René Scharfe | d7eb527 | 2009-03-07 13:28:40 +0100 | [diff] [blame] | 424 | return match_expr_eval(x, bol, eol, ctx, collect_hits); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 425 | } |
| 426 | |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 427 | static int match_line(struct grep_opt *opt, char *bol, char *eol, |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 428 | enum grep_context ctx, int collect_hits) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 429 | { |
| 430 | struct grep_pat *p; |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 431 | regmatch_t match; |
| 432 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 433 | if (opt->extended) |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 434 | return match_expr(opt, bol, eol, ctx, collect_hits); |
| 435 | |
| 436 | /* we do not call with collect_hits without being extended */ |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 437 | for (p = opt->pattern_list; p; p = p->next) { |
René Scharfe | 7921277 | 2009-03-07 13:30:27 +0100 | [diff] [blame] | 438 | if (match_one_pattern(p, bol, eol, ctx, &match, 0)) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 439 | return 1; |
| 440 | } |
| 441 | return 0; |
| 442 | } |
| 443 | |
René Scharfe | 7e8f59d | 2009-03-07 13:32:32 +0100 | [diff] [blame] | 444 | static int match_next_pattern(struct grep_pat *p, char *bol, char *eol, |
| 445 | enum grep_context ctx, |
| 446 | regmatch_t *pmatch, int eflags) |
| 447 | { |
| 448 | regmatch_t match; |
| 449 | |
| 450 | if (!match_one_pattern(p, bol, eol, ctx, &match, eflags)) |
| 451 | return 0; |
| 452 | if (match.rm_so < 0 || match.rm_eo < 0) |
| 453 | return 0; |
| 454 | if (pmatch->rm_so >= 0 && pmatch->rm_eo >= 0) { |
| 455 | if (match.rm_so > pmatch->rm_so) |
| 456 | return 1; |
| 457 | if (match.rm_so == pmatch->rm_so && match.rm_eo < pmatch->rm_eo) |
| 458 | return 1; |
| 459 | } |
| 460 | pmatch->rm_so = match.rm_so; |
| 461 | pmatch->rm_eo = match.rm_eo; |
| 462 | return 1; |
| 463 | } |
| 464 | |
| 465 | static int next_match(struct grep_opt *opt, char *bol, char *eol, |
| 466 | enum grep_context ctx, regmatch_t *pmatch, int eflags) |
| 467 | { |
| 468 | struct grep_pat *p; |
| 469 | int hit = 0; |
| 470 | |
| 471 | pmatch->rm_so = pmatch->rm_eo = -1; |
| 472 | if (bol < eol) { |
| 473 | for (p = opt->pattern_list; p; p = p->next) { |
| 474 | switch (p->token) { |
| 475 | case GREP_PATTERN: /* atom */ |
| 476 | case GREP_PATTERN_HEAD: |
| 477 | case GREP_PATTERN_BODY: |
| 478 | hit |= match_next_pattern(p, bol, eol, ctx, |
| 479 | pmatch, eflags); |
| 480 | break; |
| 481 | default: |
| 482 | break; |
| 483 | } |
| 484 | } |
| 485 | } |
| 486 | return hit; |
| 487 | } |
| 488 | |
| 489 | static void show_line(struct grep_opt *opt, char *bol, char *eol, |
| 490 | const char *name, unsigned lno, char sign) |
| 491 | { |
| 492 | int rest = eol - bol; |
| 493 | |
René Scharfe | ed24e40 | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 494 | if (opt->pre_context || opt->post_context) { |
René Scharfe | 046802d | 2009-07-02 00:03:44 +0200 | [diff] [blame] | 495 | if (opt->last_shown == 0) { |
| 496 | if (opt->show_hunk_mark) |
René Scharfe | ed24e40 | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 497 | fputs("--\n", stdout); |
René Scharfe | 046802d | 2009-07-02 00:03:44 +0200 | [diff] [blame] | 498 | else |
| 499 | opt->show_hunk_mark = 1; |
René Scharfe | ed24e40 | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 500 | } else if (lno > opt->last_shown + 1) |
| 501 | fputs("--\n", stdout); |
René Scharfe | 5dd06d3 | 2009-07-02 00:02:38 +0200 | [diff] [blame] | 502 | } |
| 503 | opt->last_shown = lno; |
| 504 | |
René Scharfe | 7e8f59d | 2009-03-07 13:32:32 +0100 | [diff] [blame] | 505 | if (opt->null_following_name) |
| 506 | sign = '\0'; |
| 507 | if (opt->pathname) |
| 508 | printf("%s%c", name, sign); |
| 509 | if (opt->linenum) |
| 510 | printf("%d%c", lno, sign); |
| 511 | if (opt->color) { |
| 512 | regmatch_t match; |
| 513 | enum grep_context ctx = GREP_CONTEXT_BODY; |
| 514 | int ch = *eol; |
| 515 | int eflags = 0; |
| 516 | |
| 517 | *eol = '\0'; |
| 518 | while (next_match(opt, bol, eol, ctx, &match, eflags)) { |
René Scharfe | 1f5b9cc | 2009-06-01 23:53:05 +0200 | [diff] [blame] | 519 | if (match.rm_so == match.rm_eo) |
| 520 | break; |
René Scharfe | 7e8f59d | 2009-03-07 13:32:32 +0100 | [diff] [blame] | 521 | printf("%.*s%s%.*s%s", |
Junio C Hamano | 747a322 | 2009-03-08 18:22:44 -0700 | [diff] [blame] | 522 | (int)match.rm_so, bol, |
René Scharfe | 7e8f59d | 2009-03-07 13:32:32 +0100 | [diff] [blame] | 523 | opt->color_match, |
Junio C Hamano | 747a322 | 2009-03-08 18:22:44 -0700 | [diff] [blame] | 524 | (int)(match.rm_eo - match.rm_so), bol + match.rm_so, |
René Scharfe | 7e8f59d | 2009-03-07 13:32:32 +0100 | [diff] [blame] | 525 | GIT_COLOR_RESET); |
| 526 | bol += match.rm_eo; |
| 527 | rest -= match.rm_eo; |
| 528 | eflags = REG_NOTBOL; |
| 529 | } |
| 530 | *eol = ch; |
| 531 | } |
| 532 | printf("%.*s\n", rest, bol); |
| 533 | } |
| 534 | |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 535 | static int match_funcname(struct grep_opt *opt, char *bol, char *eol) |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 536 | { |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 537 | xdemitconf_t *xecfg = opt->priv; |
| 538 | if (xecfg && xecfg->find_func) { |
| 539 | char buf[1]; |
| 540 | return xecfg->find_func(bol, eol - bol, buf, 1, |
| 541 | xecfg->find_func_priv) >= 0; |
| 542 | } |
| 543 | |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 544 | if (bol == eol) |
| 545 | return 0; |
| 546 | if (isalpha(*bol) || *bol == '_' || *bol == '$') |
| 547 | return 1; |
| 548 | return 0; |
| 549 | } |
| 550 | |
| 551 | static void show_funcname_line(struct grep_opt *opt, const char *name, |
| 552 | char *buf, char *bol, unsigned lno) |
| 553 | { |
| 554 | while (bol > buf) { |
| 555 | char *eol = --bol; |
| 556 | |
| 557 | while (bol > buf && bol[-1] != '\n') |
| 558 | bol--; |
| 559 | lno--; |
| 560 | |
| 561 | if (lno <= opt->last_shown) |
| 562 | break; |
| 563 | |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 564 | if (match_funcname(opt, bol, eol)) { |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 565 | show_line(opt, bol, eol, name, lno, '='); |
| 566 | break; |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 571 | static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, |
| 572 | char *bol, unsigned lno) |
| 573 | { |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 574 | unsigned cur = lno, from = 1, funcname_lno = 0; |
| 575 | int funcname_needed = opt->funcname; |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 576 | |
| 577 | if (opt->pre_context < lno) |
| 578 | from = lno - opt->pre_context; |
| 579 | if (from <= opt->last_shown) |
| 580 | from = opt->last_shown + 1; |
| 581 | |
| 582 | /* Rewind. */ |
| 583 | while (bol > buf && cur > from) { |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 584 | char *eol = --bol; |
| 585 | |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 586 | while (bol > buf && bol[-1] != '\n') |
| 587 | bol--; |
| 588 | cur--; |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 589 | if (funcname_needed && match_funcname(opt, bol, eol)) { |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 590 | funcname_lno = cur; |
| 591 | funcname_needed = 0; |
| 592 | } |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 593 | } |
| 594 | |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 595 | /* We need to look even further back to find a function signature. */ |
| 596 | if (opt->funcname && funcname_needed) |
| 597 | show_funcname_line(opt, name, buf, bol, cur); |
| 598 | |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 599 | /* Back forward. */ |
| 600 | while (cur < lno) { |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 601 | char *eol = bol, sign = (cur == funcname_lno) ? '=' : '-'; |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 602 | |
| 603 | while (*eol != '\n') |
| 604 | eol++; |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 605 | show_line(opt, bol, eol, name, cur, sign); |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 606 | bol = eol + 1; |
| 607 | cur++; |
| 608 | } |
| 609 | } |
| 610 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 611 | static int grep_buffer_1(struct grep_opt *opt, const char *name, |
| 612 | char *buf, unsigned long size, int collect_hits) |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 613 | { |
| 614 | char *bol = buf; |
| 615 | unsigned long left = size; |
| 616 | unsigned lno = 1; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 617 | unsigned last_hit = 0; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 618 | int binary_match_only = 0; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 619 | unsigned count = 0; |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 620 | enum grep_context ctx = GREP_CONTEXT_HEAD; |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 621 | xdemitconf_t xecfg; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 622 | |
René Scharfe | 5dd06d3 | 2009-07-02 00:02:38 +0200 | [diff] [blame] | 623 | opt->last_shown = 0; |
| 624 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 625 | if (buffer_is_binary(buf, size)) { |
| 626 | switch (opt->binary) { |
| 627 | case GREP_BINARY_DEFAULT: |
| 628 | binary_match_only = 1; |
| 629 | break; |
| 630 | case GREP_BINARY_NOMATCH: |
| 631 | return 0; /* Assume unmatch */ |
| 632 | break; |
| 633 | default: |
| 634 | break; |
| 635 | } |
| 636 | } |
| 637 | |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 638 | memset(&xecfg, 0, sizeof(xecfg)); |
| 639 | if (opt->funcname && !opt->unmatch_name_only && !opt->status_only && |
| 640 | !opt->name_only && !binary_match_only && !collect_hits) { |
| 641 | struct userdiff_driver *drv = userdiff_find_by_path(name); |
| 642 | if (drv && drv->funcname.pattern) { |
| 643 | const struct userdiff_funcname *pe = &drv->funcname; |
| 644 | xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); |
| 645 | opt->priv = &xecfg; |
| 646 | } |
| 647 | } |
| 648 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 649 | while (left) { |
| 650 | char *eol, ch; |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 651 | int hit; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 652 | |
| 653 | eol = end_of_line(bol, &left); |
| 654 | ch = *eol; |
| 655 | *eol = 0; |
| 656 | |
Junio C Hamano | 480c1ca | 2006-09-20 12:39:46 -0700 | [diff] [blame] | 657 | if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol)) |
| 658 | ctx = GREP_CONTEXT_BODY; |
| 659 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 660 | hit = match_line(opt, bol, eol, ctx, collect_hits); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 661 | *eol = ch; |
| 662 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 663 | if (collect_hits) |
| 664 | goto next_line; |
| 665 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 666 | /* "grep -v -e foo -e bla" should list lines |
| 667 | * that do not have either, so inversion should |
| 668 | * be done outside. |
| 669 | */ |
| 670 | if (opt->invert) |
| 671 | hit = !hit; |
| 672 | if (opt->unmatch_name_only) { |
| 673 | if (hit) |
| 674 | return 0; |
| 675 | goto next_line; |
| 676 | } |
| 677 | if (hit) { |
| 678 | count++; |
| 679 | if (opt->status_only) |
| 680 | return 1; |
| 681 | if (binary_match_only) { |
| 682 | printf("Binary file %s matches\n", name); |
| 683 | return 1; |
| 684 | } |
| 685 | if (opt->name_only) { |
Raphael Zimmerer | 83caecc | 2008-10-01 18:11:15 +0200 | [diff] [blame] | 686 | show_name(opt, name); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 687 | return 1; |
| 688 | } |
| 689 | /* Hit at this line. If we haven't shown the |
| 690 | * pre-context lines, we would need to show them. |
| 691 | * When asked to do "count", this still show |
| 692 | * the context which is nonsense, but the user |
| 693 | * deserves to get that ;-). |
| 694 | */ |
René Scharfe | 49de321 | 2009-07-02 00:05:17 +0200 | [diff] [blame] | 695 | if (opt->pre_context) |
| 696 | show_pre_context(opt, name, buf, bol, lno); |
René Scharfe | 2944e4e | 2009-07-02 00:06:34 +0200 | [diff] [blame] | 697 | else if (opt->funcname) |
| 698 | show_funcname_line(opt, name, buf, bol, lno); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 699 | if (!opt->count) |
| 700 | show_line(opt, bol, eol, name, lno, ':'); |
René Scharfe | 5dd06d3 | 2009-07-02 00:02:38 +0200 | [diff] [blame] | 701 | last_hit = lno; |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 702 | } |
| 703 | else if (last_hit && |
| 704 | lno <= last_hit + opt->post_context) { |
| 705 | /* If the last hit is within the post context, |
| 706 | * we need to show this line. |
| 707 | */ |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 708 | show_line(opt, bol, eol, name, lno, '-'); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 709 | } |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 710 | |
| 711 | next_line: |
| 712 | bol = eol + 1; |
| 713 | if (!left) |
| 714 | break; |
| 715 | left--; |
| 716 | lno++; |
| 717 | } |
| 718 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 719 | if (collect_hits) |
| 720 | return 0; |
Junio C Hamano | b48fb5b | 2006-09-27 16:27:10 -0700 | [diff] [blame] | 721 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 722 | if (opt->status_only) |
| 723 | return 0; |
| 724 | if (opt->unmatch_name_only) { |
| 725 | /* We did not see any hit, so we want to show this */ |
Raphael Zimmerer | 83caecc | 2008-10-01 18:11:15 +0200 | [diff] [blame] | 726 | show_name(opt, name); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 727 | return 1; |
| 728 | } |
| 729 | |
René Scharfe | 60ecac9 | 2009-07-02 00:07:24 +0200 | [diff] [blame] | 730 | xdiff_clear_find_func(&xecfg); |
| 731 | opt->priv = NULL; |
| 732 | |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 733 | /* NEEDSWORK: |
| 734 | * The real "grep -c foo *.c" gives many "bar.c:0" lines, |
| 735 | * which feels mostly useless but sometimes useful. Maybe |
| 736 | * make it another option? For now suppress them. |
| 737 | */ |
| 738 | if (opt->count && count) |
Raphael Zimmerer | 83caecc | 2008-10-01 18:11:15 +0200 | [diff] [blame] | 739 | printf("%s%c%u\n", name, |
| 740 | opt->null_following_name ? '\0' : ':', count); |
Junio C Hamano | 83b5d2f | 2006-09-17 16:02:52 -0700 | [diff] [blame] | 741 | return !!last_hit; |
| 742 | } |
| 743 | |
Junio C Hamano | 0ab7bef | 2006-09-27 17:50:52 -0700 | [diff] [blame] | 744 | static void clr_hit_marker(struct grep_expr *x) |
| 745 | { |
| 746 | /* All-hit markers are meaningful only at the very top level |
| 747 | * OR node. |
| 748 | */ |
| 749 | while (1) { |
| 750 | x->hit = 0; |
| 751 | if (x->node != GREP_NODE_OR) |
| 752 | return; |
| 753 | x->u.binary.left->hit = 0; |
| 754 | x = x->u.binary.right; |
| 755 | } |
| 756 | } |
| 757 | |
| 758 | static int chk_hit_marker(struct grep_expr *x) |
| 759 | { |
| 760 | /* Top level nodes have hit markers. See if they all are hits */ |
| 761 | while (1) { |
| 762 | if (x->node != GREP_NODE_OR) |
| 763 | return x->hit; |
| 764 | if (!x->u.binary.left->hit) |
| 765 | return 0; |
| 766 | x = x->u.binary.right; |
| 767 | } |
| 768 | } |
| 769 | |
| 770 | int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size) |
| 771 | { |
| 772 | /* |
| 773 | * we do not have to do the two-pass grep when we do not check |
| 774 | * buffer-wide "all-match". |
| 775 | */ |
| 776 | if (!opt->all_match) |
| 777 | return grep_buffer_1(opt, name, buf, size, 0); |
| 778 | |
| 779 | /* Otherwise the toplevel "or" terms hit a bit differently. |
| 780 | * We first clear hit markers from them. |
| 781 | */ |
| 782 | clr_hit_marker(opt->pattern_expression); |
| 783 | grep_buffer_1(opt, name, buf, size, 1); |
| 784 | |
| 785 | if (!chk_hit_marker(opt->pattern_expression)) |
| 786 | return 0; |
| 787 | |
| 788 | return grep_buffer_1(opt, name, buf, size, 0); |
| 789 | } |