Skip to content

Commit

Permalink
Merge branch 'rs/grep-p'
Browse files Browse the repository at this point in the history
* rs/grep-p:
  grep: simplify -p output
  grep -p: support user defined regular expressions
  grep: add option -p/--show-function
  grep: handle pre context lines on demand
  grep: print context hunk marks between files
  grep: move context hunk mark handling into show_line()
  userdiff: add xdiff_clear_find_func()
  • Loading branch information
Junio C Hamano committed Jul 9, 2009
2 parents ce4f404 + ed24e40 commit 128a9d8
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 44 deletions.
8 changes: 8 additions & 0 deletions Documentation/git-grep.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ OPTIONS
-<num>::
A shortcut for specifying -C<num>.

-p::
--show-function::
Show the preceding line that contains the function name of
the match, unless the matching line is a function name itself.
The name is determined in the same way as 'git diff' works out
patch hunk headers (see 'Defining a custom hunk-header' in
linkgit:gitattributes[5]).

-f <file>::
Read patterns from <file>, one per line.

Expand Down
22 changes: 21 additions & 1 deletion builtin-grep.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "tree-walk.h"
#include "builtin.h"
#include "parse-options.h"
#include "userdiff.h"
#include "grep.h"

#ifndef NO_EXTERNAL_GREP
Expand All @@ -30,6 +31,12 @@ static int grep_config(const char *var, const char *value, void *cb)
{
struct grep_opt *opt = cb;

switch (userdiff_config(var, value)) {
case 0: break;
case -1: return -1;
default: return 0;
}

if (!strcmp(var, "color.grep")) {
opt->color = git_config_colorbool(var, value, -1);
return 0;
Expand Down Expand Up @@ -278,6 +285,17 @@ static int flush_grep(struct grep_opt *opt,
argc -= 2;
}

if (opt->pre_context || opt->post_context) {
/*
* grep handles hunk marks between files, but we need to
* do that ourselves between multiple calls.
*/
if (opt->show_hunk_mark)
write_or_die(1, "--\n", 3);
else
opt->show_hunk_mark = 1;
}

status = exec_grep(argc, argv);

if (kept_0) {
Expand Down Expand Up @@ -710,6 +728,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
"show <n> context lines after matches"),
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
context_callback),
OPT_BOOLEAN('p', "show-function", &opt.funcname,
"show a line with the function name before matches"),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, "file",
"read patterns from file", file_callback),
Expand Down Expand Up @@ -778,7 +798,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
argc--;
}

if (opt.color && !opt.color_external)
if ((opt.color && !opt.color_external) || opt.funcname)
external_grep_allowed = 0;
if (!opt.pattern_list)
die("no pattern given.");
Expand Down
1 change: 1 addition & 0 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,7 @@ static void builtin_diff(const char *name_a,
free(mf1.ptr);
if (textconv_two)
free(mf2.ptr);
xdiff_clear_find_func(&xecfg);
}

free_ab_and_return:
Expand Down
150 changes: 109 additions & 41 deletions grep.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "cache.h"
#include "grep.h"
#include "userdiff.h"
#include "xdiff-interface.h"

void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)
Expand Down Expand Up @@ -490,6 +491,17 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
{
int rest = eol - bol;

if (opt->pre_context || opt->post_context) {
if (opt->last_shown == 0) {
if (opt->show_hunk_mark)
fputs("--\n", stdout);
else
opt->show_hunk_mark = 1;
} else if (lno > opt->last_shown + 1)
fputs("--\n", stdout);
}
opt->last_shown = lno;

if (opt->null_following_name)
sign = '\0';
if (opt->pathname)
Expand Down Expand Up @@ -520,22 +532,95 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
printf("%.*s\n", rest, bol);
}

static int match_funcname(struct grep_opt *opt, char *bol, char *eol)
{
xdemitconf_t *xecfg = opt->priv;
if (xecfg && xecfg->find_func) {
char buf[1];
return xecfg->find_func(bol, eol - bol, buf, 1,
xecfg->find_func_priv) >= 0;
}

if (bol == eol)
return 0;
if (isalpha(*bol) || *bol == '_' || *bol == '$')
return 1;
return 0;
}

static void show_funcname_line(struct grep_opt *opt, const char *name,
char *buf, char *bol, unsigned lno)
{
while (bol > buf) {
char *eol = --bol;

while (bol > buf && bol[-1] != '\n')
bol--;
lno--;

if (lno <= opt->last_shown)
break;

if (match_funcname(opt, bol, eol)) {
show_line(opt, bol, eol, name, lno, '=');
break;
}
}
}

static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
char *bol, unsigned lno)
{
unsigned cur = lno, from = 1, funcname_lno = 0;
int funcname_needed = opt->funcname;

if (opt->pre_context < lno)
from = lno - opt->pre_context;
if (from <= opt->last_shown)
from = opt->last_shown + 1;

/* Rewind. */
while (bol > buf && cur > from) {
char *eol = --bol;

while (bol > buf && bol[-1] != '\n')
bol--;
cur--;
if (funcname_needed && match_funcname(opt, bol, eol)) {
funcname_lno = cur;
funcname_needed = 0;
}
}

/* We need to look even further back to find a function signature. */
if (opt->funcname && funcname_needed)
show_funcname_line(opt, name, buf, bol, cur);

/* Back forward. */
while (cur < lno) {
char *eol = bol, sign = (cur == funcname_lno) ? '=' : '-';

while (*eol != '\n')
eol++;
show_line(opt, bol, eol, name, cur, sign);
bol = eol + 1;
cur++;
}
}

static int grep_buffer_1(struct grep_opt *opt, const char *name,
char *buf, unsigned long size, int collect_hits)
{
char *bol = buf;
unsigned long left = size;
unsigned lno = 1;
struct pre_context_line {
char *bol;
char *eol;
} *prev = NULL, *pcl;
unsigned last_hit = 0;
unsigned last_shown = 0;
int binary_match_only = 0;
const char *hunk_mark = "";
unsigned count = 0;
enum grep_context ctx = GREP_CONTEXT_HEAD;
xdemitconf_t xecfg;

opt->last_shown = 0;

if (buffer_is_binary(buf, size)) {
switch (opt->binary) {
Expand All @@ -550,10 +635,16 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
}
}

if (opt->pre_context)
prev = xcalloc(opt->pre_context, sizeof(*prev));
if (opt->pre_context || opt->post_context)
hunk_mark = "--\n";
memset(&xecfg, 0, sizeof(xecfg));
if (opt->funcname && !opt->unmatch_name_only && !opt->status_only &&
!opt->name_only && !binary_match_only && !collect_hits) {
struct userdiff_driver *drv = userdiff_find_by_path(name);
if (drv && drv->funcname.pattern) {
const struct userdiff_funcname *pe = &drv->funcname;
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
opt->priv = &xecfg;
}
}

while (left) {
char *eol, ch;
Expand Down Expand Up @@ -601,45 +692,20 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
* the context which is nonsense, but the user
* deserves to get that ;-).
*/
if (opt->pre_context) {
unsigned from;
if (opt->pre_context < lno)
from = lno - opt->pre_context;
else
from = 1;
if (from <= last_shown)
from = last_shown + 1;
if (last_shown && from != last_shown + 1)
fputs(hunk_mark, stdout);
while (from < lno) {
pcl = &prev[lno-from-1];
show_line(opt, pcl->bol, pcl->eol,
name, from, '-');
from++;
}
last_shown = lno-1;
}
if (last_shown && lno != last_shown + 1)
fputs(hunk_mark, stdout);
if (opt->pre_context)
show_pre_context(opt, name, buf, bol, lno);
else if (opt->funcname)
show_funcname_line(opt, name, buf, bol, lno);
if (!opt->count)
show_line(opt, bol, eol, name, lno, ':');
last_shown = last_hit = lno;
last_hit = lno;
}
else if (last_hit &&
lno <= last_hit + opt->post_context) {
/* If the last hit is within the post context,
* we need to show this line.
*/
if (last_shown && lno != last_shown + 1)
fputs(hunk_mark, stdout);
show_line(opt, bol, eol, name, lno, '-');
last_shown = lno;
}
if (opt->pre_context) {
memmove(prev+1, prev,
(opt->pre_context-1) * sizeof(*prev));
prev->bol = bol;
prev->eol = eol;
}

next_line:
Expand All @@ -650,7 +716,6 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
lno++;
}

free(prev);
if (collect_hits)
return 0;

Expand All @@ -662,6 +727,9 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
return 1;
}

xdiff_clear_find_func(&xecfg);
opt->priv = NULL;

/* NEEDSWORK:
* The real "grep -c foo *.c" gives many "bar.c:0" lines,
* which feels mostly useless but sometimes useful. Maybe
Expand Down
4 changes: 4 additions & 0 deletions grep.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ struct grep_opt {
int pathname;
int null_following_name;
int color;
int funcname;
char color_match[COLOR_MAXLEN];
const char *color_external;
int regflags;
unsigned pre_context;
unsigned post_context;
unsigned last_shown;
int show_hunk_mark;
void *priv;
};

extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
Expand Down
Loading

0 comments on commit 128a9d8

Please sign in to comment.