static int grep_tree(struct grep_opt *opt, const char **paths, struct tree_desc *tree, const char *tree_name, const char *base) { int len; int hit = 0; struct name_entry entry; char *down; int tn_len = strlen(tree_name); struct strbuf pathbuf; strbuf_init(&pathbuf, PATH_MAX + tn_len); if (tn_len) { strbuf_add(&pathbuf, tree_name, tn_len); strbuf_addch(&pathbuf, ':'); tn_len = pathbuf.len; } strbuf_addstr(&pathbuf, base); len = pathbuf.len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); pathbuf.len = len; strbuf_add(&pathbuf, entry.path, te_len); if (S_ISDIR(entry.mode)) /* Match "abc/" against pathspec to * decide if we want to descend into "abc" * directory. */ strbuf_addch(&pathbuf, '/'); down = pathbuf.buf + tn_len; if (!pathspec_matches(paths, down, opt->max_depth)) ; else if (S_ISREG(entry.mode)) hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; unsigned long size; data = lock_and_read_sha1_file(entry.sha1, &type, &size); if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, paths, &sub, tree_name, down); free(data); } if (hit && opt->status_only) break; } strbuf_release(&pathbuf); return hit; }
static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; int nr; read_cache(); #if !NO_EXTERNAL_GREP /* * Use the external "grep" command for the case where * we grep through the checked-out files. It tends to * be a lot more optimized */ if (!cached && !builtin_grep) { hit = external_grep(opt, paths, cached); if (hit >= 0) return hit; } #endif for (nr = 0; nr < active_nr; nr++) { struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; if (!pathspec_matches(paths, ce->name)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use * cache version instead */ if (cached || (ce->ce_flags & CE_VALID)) { if (ce_stage(ce)) continue; hit |= grep_sha1(opt, ce->sha1, ce->name, 0); } else hit |= grep_file(opt, ce->name); if (ce_stage(ce)) { do { nr++; } while (nr < active_nr && !strcmp(ce->name, active_cache[nr]->name)); nr--; /* compensate for loop control */ } } free_grep_patterns(opt); return hit; }
static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; int nr; read_cache(); for (nr = 0; nr < active_nr; nr++) { struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; if (!pathspec_matches(paths, ce->name, opt->max_depth)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use * cache version instead */ if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) { if (ce_stage(ce)) continue; hit |= grep_sha1(opt, ce->sha1, ce->name, 0); } else hit |= grep_file(opt, ce->name); if (ce_stage(ce)) { do { nr++; } while (nr < active_nr && !strcmp(ce->name, active_cache[nr]->name)); nr--; /* compensate for loop control */ } if (hit && opt->status_only) break; } free_grep_patterns(opt); return hit; }
static int external_grep(struct grep_opt *opt, const char **paths, int cached) { int i, nr, argc, hit, len, status; const char *argv[MAXARGS+1]; char randarg[ARGBUF]; char *argptr = randarg; struct grep_pat *p; if (opt->extended || (opt->relative && opt->prefix_length)) return -1; len = nr = 0; push_arg("grep"); if (opt->fixed) push_arg("-F"); if (opt->linenum) push_arg("-n"); if (!opt->pathname) push_arg("-h"); if (opt->regflags & REG_EXTENDED) push_arg("-E"); if (opt->regflags & REG_ICASE) push_arg("-i"); if (opt->binary == GREP_BINARY_NOMATCH) push_arg("-I"); if (opt->word_regexp) push_arg("-w"); if (opt->name_only) push_arg("-l"); if (opt->unmatch_name_only) push_arg("-L"); if (opt->null_following_name) /* in GNU grep git's "-z" translates to "-Z" */ push_arg("-Z"); if (opt->count) push_arg("-c"); if (opt->post_context || opt->pre_context) { if (opt->post_context != opt->pre_context) { if (opt->pre_context) { push_arg("-B"); len += snprintf(argptr, sizeof(randarg)-len, "%u", opt->pre_context) + 1; if (sizeof(randarg) <= len) die("maximum length of args exceeded"); push_arg(argptr); argptr += len; } if (opt->post_context) { push_arg("-A"); len += snprintf(argptr, sizeof(randarg)-len, "%u", opt->post_context) + 1; if (sizeof(randarg) <= len) die("maximum length of args exceeded"); push_arg(argptr); argptr += len; } } else { push_arg("-C"); len += snprintf(argptr, sizeof(randarg)-len, "%u", opt->post_context) + 1; if (sizeof(randarg) <= len) die("maximum length of args exceeded"); push_arg(argptr); argptr += len; } } for (p = opt->pattern_list; p; p = p->next) { push_arg("-e"); push_arg(p->pattern); } hit = 0; argc = nr; for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; char *name; int kept; if (!S_ISREG(ce->ce_mode)) continue; if (!pathspec_matches(paths, ce->name)) continue; name = ce->name; if (name[0] == '-') { int len = ce_namelen(ce); name = xmalloc(len + 3); memcpy(name, "./", 2); memcpy(name + 2, ce->name, len + 1); } argv[argc++] = name; if (MAXARGS <= argc) { status = flush_grep(opt, argc, nr, argv, &kept); if (0 < status) hit = 1; argc = nr + kept; } if (ce_stage(ce)) { do { i++; } while (i < active_nr && !strcmp(ce->name, active_cache[i]->name)); i--; /* compensate for loop control */ } } if (argc > nr) { status = flush_grep(opt, argc, nr, argv, NULL); if (0 < status) hit = 1; } return hit; }