4 * Copyright (c) 2006 Junio C Hamano
16 static int pathspec_matches(struct diff_options
*opt
, const char *name
)
22 namelen
= strlen(name
);
23 for (i
= 0; i
< opt
->nr_paths
; i
++) {
24 const char *match
= opt
->paths
[i
];
25 int matchlen
= opt
->pathlens
[i
];
26 if (matchlen
<= namelen
) {
27 if (!strncmp(name
, match
, matchlen
))
31 /* If name is "Documentation" and pathspec is
32 * "Documentation/", they should match. Maybe
33 * we would want to strip it in get_pathspec()???
35 if (strncmp(name
, match
, namelen
))
37 for (j
= namelen
; j
< matchlen
; j
++)
53 unsigned post_context
;
56 static char *end_of_line(char *cp
, unsigned long *left
)
58 unsigned long l
= *left
;
59 while (l
&& *cp
!= '\n') {
67 static void show_line(struct grep_opt
*opt
, const char *bol
, const char *eol
,
68 const char *name
, unsigned lno
, char sign
)
70 printf("%s%c", name
, sign
);
72 printf("%d%c", lno
, sign
);
73 printf("%.*s\n", eol
-bol
, bol
);
76 static int grep_buffer(struct grep_opt
*opt
, const char *name
,
77 char *buf
, unsigned long size
)
80 unsigned long left
= size
;
82 struct pre_context_line
{
86 unsigned last_hit
= 0;
87 unsigned last_shown
= 0;
88 const char *hunk_mark
= "";
91 prev
= xcalloc(opt
->pre_context
, sizeof(*prev
));
92 if (opt
->pre_context
|| opt
->post_context
)
96 regmatch_t pmatch
[10];
100 eol
= end_of_line(bol
, &left
);
104 hit
= !regexec(&opt
->regexp
, bol
, ARRAY_SIZE(pmatch
),
109 /* Hit at this line. If we haven't shown the
110 * pre-context lines, we would need to show them.
112 if (opt
->pre_context
) {
114 if (opt
->pre_context
< lno
)
115 from
= lno
- opt
->pre_context
;
118 if (from
<= last_shown
)
119 from
= last_shown
+ 1;
120 if (last_shown
&& from
!= last_shown
+ 1)
123 pcl
= &prev
[lno
-from
-1];
124 show_line(opt
, pcl
->bol
, pcl
->eol
,
130 if (last_shown
&& lno
!= last_shown
+ 1)
132 show_line(opt
, bol
, eol
, name
, lno
, ':');
133 last_shown
= last_hit
= lno
;
136 lno
<= last_hit
+ opt
->post_context
) {
137 /* If the last hit is within the post context,
138 * we need to show this line.
140 if (last_shown
&& lno
!= last_shown
+ 1)
142 show_line(opt
, bol
, eol
, name
, lno
, '-');
145 if (opt
->pre_context
) {
146 memmove(prev
+1, prev
,
147 (opt
->pre_context
-1) * sizeof(*prev
));
159 static int grep_sha1(struct grep_opt
*opt
, const unsigned char *sha1
, const char *name
)
165 data
= read_sha1_file(sha1
, type
, &size
);
167 error("'%s': unable to read %s", name
, sha1_to_hex(sha1
));
170 hit
= grep_buffer(opt
, name
, data
, size
);
175 static int grep_file(struct grep_opt
*opt
, const char *filename
)
180 if (lstat(filename
, &st
) < 0) {
183 error("'%s': %s", filename
, strerror(errno
));
187 return 0; /* empty file -- no grep hit */
188 if (!S_ISREG(st
.st_mode
))
190 i
= open(filename
, O_RDONLY
);
193 data
= xmalloc(st
.st_size
+ 1);
194 if (st
.st_size
!= xread(i
, data
, st
.st_size
)) {
195 error("'%s': short read %s", filename
, strerror(errno
));
201 i
= grep_buffer(opt
, filename
, data
, st
.st_size
);
206 static int grep_cache(struct grep_opt
*opt
, struct rev_info
*revs
, int cached
)
212 for (nr
= 0; nr
< active_nr
; nr
++) {
213 struct cache_entry
*ce
= active_cache
[nr
];
214 if (ce_stage(ce
) || !S_ISREG(ntohl(ce
->ce_mode
)))
216 if (!pathspec_matches(&revs
->diffopt
, ce
->name
))
219 hit
|= grep_sha1(opt
, ce
->sha1
, ce
->name
);
221 hit
|= grep_file(opt
, ce
->name
);
226 static int grep_tree(struct grep_opt
*opt
, struct rev_info
*revs
,
227 struct tree_desc
*tree
,
228 const char *tree_name
, const char *base
)
234 const unsigned char *sha1
;
236 char *path_buf
= xmalloc(PATH_MAX
+ strlen(tree_name
) + 100);
239 int offset
= sprintf(path_buf
, "%s:", tree_name
);
240 down_base
= path_buf
+ offset
;
241 strcat(down_base
, base
);
244 down_base
= path_buf
;
245 strcpy(down_base
, base
);
247 len
= strlen(path_buf
);
251 sha1
= tree_entry_extract(tree
, &path
, &mode
);
252 pathlen
= strlen(path
);
253 strcpy(path_buf
+ len
, path
);
255 if (!pathspec_matches(&revs
->diffopt
, down_base
))
257 else if (S_ISREG(mode
))
258 hit
|= grep_sha1(opt
, sha1
, path_buf
);
259 else if (S_ISDIR(mode
)) {
261 struct tree_desc sub
;
263 data
= read_sha1_file(sha1
, type
, &sub
.size
);
265 die("unable to read tree (%s)",
267 strcpy(path_buf
+ len
+ pathlen
, "/");
269 hit
= grep_tree(opt
, revs
, &sub
, tree_name
, down_base
);
272 update_tree_entry(tree
);
277 static int grep_object(struct grep_opt
*opt
, struct rev_info
*revs
,
278 struct object
*obj
, const char *name
)
280 if (!strcmp(obj
->type
, blob_type
))
281 return grep_sha1(opt
, obj
->sha1
, name
);
282 if (!strcmp(obj
->type
, commit_type
) ||
283 !strcmp(obj
->type
, tree_type
)) {
284 struct tree_desc tree
;
287 data
= read_object_with_reference(obj
->sha1
, tree_type
,
290 die("unable to read tree (%s)", sha1_to_hex(obj
->sha1
));
292 hit
= grep_tree(opt
, revs
, &tree
, name
, "");
296 die("unable to grep from object of type %s", obj
->type
);
299 static const char builtin_grep_usage
[] =
300 "git-grep <option>* <rev>* [-e] <pattern> [<path>...]";
302 int cmd_grep(int argc
, const char **argv
, char **envp
)
305 const char **dst
, **src
;
310 int seen_noncommit
= 0;
313 struct object_list
*list
;
315 memset(&opt
, 0, sizeof(opt
));
316 opt
.regflags
= REG_NEWLINE
;
319 * Interpret and remove the grep options upfront. Sigh...
321 for (dst
= src
= &argv
[1]; src
< argc
+ argv
; ) {
322 const char *arg
= *src
++;
324 if (!strcmp("--", arg
)) {
329 if (!strcmp("--cached", arg
)) {
333 if (!strcmp("-i", arg
) ||
334 !strcmp("--ignore-case", arg
)) {
335 opt
.regflags
|= REG_ICASE
;
338 if (!strcmp("-v", arg
) ||
339 !strcmp("--invert-match", arg
)) {
343 if (!strcmp("-E", arg
) ||
344 !strcmp("--extended-regexp", arg
)) {
345 opt
.regflags
|= REG_EXTENDED
;
348 if (!strcmp("-G", arg
) ||
349 !strcmp("--basic-regexp", arg
)) {
350 opt
.regflags
&= ~REG_EXTENDED
;
353 if (!strcmp("-e", arg
)) {
354 if (src
< argc
+ argv
) {
355 opt
.pattern
= *src
++;
358 usage(builtin_grep_usage
);
360 if (!strcmp("-n", arg
)) {
364 if (!strcmp("-H", arg
)) {
365 /* We always show the pathname, so this
370 if (!strcmp("-A", arg
) ||
371 !strcmp("-B", arg
) ||
372 !strcmp("-C", arg
)) {
374 if ((argc
+ argv
<= src
) ||
375 sscanf(*src
++, "%u", &num
) != 1)
376 usage(builtin_grep_usage
);
379 opt
.post_context
= num
;
382 opt
.post_context
= num
;
384 opt
.pre_context
= num
;
393 die("no pattern given.");
395 err
= regcomp(&opt
.regexp
, opt
.pattern
, opt
.regflags
);
398 regerror(err
, &opt
.regexp
, errbuf
, 1024);
399 regfree(&opt
.regexp
);
400 die("'%s': %s", opt
.pattern
, errbuf
);
403 init_revisions(&rev
);
405 argc
= setup_revisions(dst
- argv
, argv
, &rev
, NULL
);
408 * Do not walk "grep -e foo master next pu -- Documentation/"
409 * but do walk "grep -e foo master..next -- Documentation/".
410 * Ranged request mixed with a blob or tree object, like
411 * "grep -e foo v1.0.0:Documentation/ master..next"
412 * so detect that and complain.
414 for (list
= rev
.pending_objects
; list
; list
= list
->next
) {
415 struct object
*real_obj
;
416 if (list
->item
->flags
& UNINTERESTING
)
418 real_obj
= deref_tag(list
->item
, NULL
, 0);
419 if (strcmp(real_obj
->type
, commit_type
))
422 if (!rev
.pending_objects
)
423 return !grep_cache(&opt
, &rev
, cached
);
425 die("both --cached and revisions given.");
427 if (seen_range
&& seen_noncommit
)
428 die("both A..B and non commit are given.");
430 struct commit
*commit
;
431 prepare_revision_walk(&rev
);
432 while ((commit
= get_revision(&rev
)) != NULL
) {
433 unsigned char *sha1
= commit
->object
.sha1
;
434 const char *n
= find_unique_abbrev(sha1
, rev
.abbrev
);
437 if (grep_object(&opt
, &rev
, &commit
->object
, rev_name
))
439 commit
->buffer
= NULL
;
444 /* all of them are non-commit; do not walk, and
445 * do not lose their names.
447 for (list
= rev
.pending_objects
; list
; list
= list
->next
) {
448 struct object
*real_obj
;
449 real_obj
= deref_tag(list
->item
, NULL
, 0);
450 if (grep_object(&opt
, &rev
, real_obj
, list
->name
))