2006-09-18 07:02:52 +08:00
|
|
|
#ifndef GREP_H
|
|
|
|
#define GREP_H
|
2009-03-07 20:32:32 +08:00
|
|
|
#include "color.h"
|
2011-05-10 05:52:05 +08:00
|
|
|
#ifdef USE_LIBPCRE
|
|
|
|
#include <pcre.h>
|
|
|
|
#else
|
|
|
|
typedef int pcre;
|
|
|
|
typedef int pcre_extra;
|
|
|
|
#endif
|
Use kwset in grep
Benchmarks for the hot cache case:
before:
$ perf stat --repeat=5 git grep qwerty > /dev/null
Performance counter stats for 'git grep qwerty' (5 runs):
3,478,085 cache-misses # 2.322 M/sec ( +- 2.690% )
11,356,177 cache-references # 7.582 M/sec ( +- 2.598% )
3,872,184 branch-misses # 0.363 % ( +- 0.258% )
1,067,367,848 branches # 712.673 M/sec ( +- 2.622% )
3,828,370,782 instructions # 0.947 IPC ( +- 0.033% )
4,043,832,831 cycles # 2700.037 M/sec ( +- 0.167% )
8,518 page-faults # 0.006 M/sec ( +- 3.648% )
847 CPU-migrations # 0.001 M/sec ( +- 3.262% )
6,546 context-switches # 0.004 M/sec ( +- 2.292% )
1497.695495 task-clock-msecs # 3.303 CPUs ( +- 2.550% )
0.453394396 seconds time elapsed ( +- 0.912% )
after:
$ perf stat --repeat=5 git grep qwerty > /dev/null
Performance counter stats for 'git grep qwerty' (5 runs):
2,989,918 cache-misses # 3.166 M/sec ( +- 5.013% )
10,986,041 cache-references # 11.633 M/sec ( +- 4.899% ) (scaled from 95.06%)
3,511,993 branch-misses # 1.422 % ( +- 0.785% )
246,893,561 branches # 261.433 M/sec ( +- 3.967% )
1,392,727,757 instructions # 0.564 IPC ( +- 0.040% )
2,468,142,397 cycles # 2613.494 M/sec ( +- 0.110% )
7,747 page-faults # 0.008 M/sec ( +- 3.995% )
897 CPU-migrations # 0.001 M/sec ( +- 2.383% )
6,535 context-switches # 0.007 M/sec ( +- 1.993% )
944.384228 task-clock-msecs # 3.177 CPUs ( +- 0.268% )
0.297257643 seconds time elapsed ( +- 0.450% )
So we gain about 35% by using the kwset code.
As a side effect of using kwset two grep tests are fixed by this
patch. The first is fixed because kwset can deal with case-insensitive
search containing NULs, something strcasestr cannot do. The second one
is fixed because we consider patterns containing NULs as fixed strings
(regcomp cannot accept patterns with NULs).
Signed-off-by: Fredrik Kuivinen <frekui@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-21 06:42:18 +08:00
|
|
|
#include "kwset.h"
|
2011-12-13 05:16:07 +08:00
|
|
|
#include "thread-utils.h"
|
2006-09-18 07:02:52 +08:00
|
|
|
|
|
|
|
enum grep_pat_token {
|
|
|
|
GREP_PATTERN,
|
2006-09-21 03:39:46 +08:00
|
|
|
GREP_PATTERN_HEAD,
|
|
|
|
GREP_PATTERN_BODY,
|
2006-09-18 07:02:52 +08:00
|
|
|
GREP_AND,
|
|
|
|
GREP_OPEN_PAREN,
|
|
|
|
GREP_CLOSE_PAREN,
|
|
|
|
GREP_NOT,
|
2010-05-14 17:31:35 +08:00
|
|
|
GREP_OR
|
2006-09-18 07:02:52 +08:00
|
|
|
};
|
|
|
|
|
2006-09-21 03:39:46 +08:00
|
|
|
enum grep_context {
|
|
|
|
GREP_CONTEXT_HEAD,
|
2010-05-14 17:31:35 +08:00
|
|
|
GREP_CONTEXT_BODY
|
2006-09-21 03:39:46 +08:00
|
|
|
};
|
|
|
|
|
log --author/--committer: really match only with name part
When we tried to find commits done by AUTHOR, the first implementation
tried to pattern match a line with "^author .*AUTHOR", which later was
enhanced to strip leading caret and look for "^author AUTHOR" when the
search pattern was anchored at the left end (i.e. --author="^AUTHOR").
This had a few problems:
* When looking for fixed strings (e.g. "git log -F --author=x --grep=y"),
the regexp internally used "^author .*x" would never match anything;
* To match at the end (e.g. "git log --author='google.com>$'"), the
generated regexp has to also match the trailing timestamp part the
commit header lines have. Also, in order to determine if the '$' at
the end means "match at the end of the line" or just a literal dollar
sign (probably backslash-quoted), we would need to parse the regexp
ourselves.
An earlier alternative tried to make sure that a line matches "^author "
(to limit by field name) and the user supplied pattern at the same time.
While it solved the -F problem by introducing a special override for
matching the "^author ", it did not solve the trailing timestamp nor tail
match problem. It also would have matched every commit if --author=author
was asked for, not because the author's email part had this string, but
because every commit header line that talks about the author begins with
that field name, regardleses of who wrote it.
Instead of piling more hacks on top of hacks, this rethinks the grep
machinery that is used to look for strings in the commit header, and makes
sure that (1) field name matches literally at the beginning of the line,
followed by a SP, and (2) the user supplied pattern is matched against the
remainder of the line, excluding the trailing timestamp data.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
|
|
|
enum grep_header_field {
|
|
|
|
GREP_HEADER_AUTHOR = 0,
|
2010-05-14 17:31:35 +08:00
|
|
|
GREP_HEADER_COMMITTER
|
log --author/--committer: really match only with name part
When we tried to find commits done by AUTHOR, the first implementation
tried to pattern match a line with "^author .*AUTHOR", which later was
enhanced to strip leading caret and look for "^author AUTHOR" when the
search pattern was anchored at the left end (i.e. --author="^AUTHOR").
This had a few problems:
* When looking for fixed strings (e.g. "git log -F --author=x --grep=y"),
the regexp internally used "^author .*x" would never match anything;
* To match at the end (e.g. "git log --author='google.com>$'"), the
generated regexp has to also match the trailing timestamp part the
commit header lines have. Also, in order to determine if the '$' at
the end means "match at the end of the line" or just a literal dollar
sign (probably backslash-quoted), we would need to parse the regexp
ourselves.
An earlier alternative tried to make sure that a line matches "^author "
(to limit by field name) and the user supplied pattern at the same time.
While it solved the -F problem by introducing a special override for
matching the "^author ", it did not solve the trailing timestamp nor tail
match problem. It also would have matched every commit if --author=author
was asked for, not because the author's email part had this string, but
because every commit header line that talks about the author begins with
that field name, regardleses of who wrote it.
Instead of piling more hacks on top of hacks, this rethinks the grep
machinery that is used to look for strings in the commit header, and makes
sure that (1) field name matches literally at the beginning of the line,
followed by a SP, and (2) the user supplied pattern is matched against the
remainder of the line, excluding the trailing timestamp data.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
|
|
|
};
|
2010-09-13 13:15:35 +08:00
|
|
|
#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
|
log --author/--committer: really match only with name part
When we tried to find commits done by AUTHOR, the first implementation
tried to pattern match a line with "^author .*AUTHOR", which later was
enhanced to strip leading caret and look for "^author AUTHOR" when the
search pattern was anchored at the left end (i.e. --author="^AUTHOR").
This had a few problems:
* When looking for fixed strings (e.g. "git log -F --author=x --grep=y"),
the regexp internally used "^author .*x" would never match anything;
* To match at the end (e.g. "git log --author='google.com>$'"), the
generated regexp has to also match the trailing timestamp part the
commit header lines have. Also, in order to determine if the '$' at
the end means "match at the end of the line" or just a literal dollar
sign (probably backslash-quoted), we would need to parse the regexp
ourselves.
An earlier alternative tried to make sure that a line matches "^author "
(to limit by field name) and the user supplied pattern at the same time.
While it solved the -F problem by introducing a special override for
matching the "^author ", it did not solve the trailing timestamp nor tail
match problem. It also would have matched every commit if --author=author
was asked for, not because the author's email part had this string, but
because every commit header line that talks about the author begins with
that field name, regardleses of who wrote it.
Instead of piling more hacks on top of hacks, this rethinks the grep
machinery that is used to look for strings in the commit header, and makes
sure that (1) field name matches literally at the beginning of the line,
followed by a SP, and (2) the user supplied pattern is matched against the
remainder of the line, excluding the trailing timestamp data.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
|
|
|
|
2006-09-18 07:02:52 +08:00
|
|
|
struct grep_pat {
|
|
|
|
struct grep_pat *next;
|
|
|
|
const char *origin;
|
|
|
|
int no;
|
|
|
|
enum grep_pat_token token;
|
|
|
|
const char *pattern;
|
2010-05-23 05:43:43 +08:00
|
|
|
size_t patternlen;
|
log --author/--committer: really match only with name part
When we tried to find commits done by AUTHOR, the first implementation
tried to pattern match a line with "^author .*AUTHOR", which later was
enhanced to strip leading caret and look for "^author AUTHOR" when the
search pattern was anchored at the left end (i.e. --author="^AUTHOR").
This had a few problems:
* When looking for fixed strings (e.g. "git log -F --author=x --grep=y"),
the regexp internally used "^author .*x" would never match anything;
* To match at the end (e.g. "git log --author='google.com>$'"), the
generated regexp has to also match the trailing timestamp part the
commit header lines have. Also, in order to determine if the '$' at
the end means "match at the end of the line" or just a literal dollar
sign (probably backslash-quoted), we would need to parse the regexp
ourselves.
An earlier alternative tried to make sure that a line matches "^author "
(to limit by field name) and the user supplied pattern at the same time.
While it solved the -F problem by introducing a special override for
matching the "^author ", it did not solve the trailing timestamp nor tail
match problem. It also would have matched every commit if --author=author
was asked for, not because the author's email part had this string, but
because every commit header line that talks about the author begins with
that field name, regardleses of who wrote it.
Instead of piling more hacks on top of hacks, this rethinks the grep
machinery that is used to look for strings in the commit header, and makes
sure that (1) field name matches literally at the beginning of the line,
followed by a SP, and (2) the user supplied pattern is matched against the
remainder of the line, excluding the trailing timestamp data.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
|
|
|
enum grep_header_field field;
|
2006-09-18 07:02:52 +08:00
|
|
|
regex_t regexp;
|
2011-05-10 05:52:05 +08:00
|
|
|
pcre *pcre_regexp;
|
|
|
|
pcre_extra *pcre_extra_info;
|
Use kwset in grep
Benchmarks for the hot cache case:
before:
$ perf stat --repeat=5 git grep qwerty > /dev/null
Performance counter stats for 'git grep qwerty' (5 runs):
3,478,085 cache-misses # 2.322 M/sec ( +- 2.690% )
11,356,177 cache-references # 7.582 M/sec ( +- 2.598% )
3,872,184 branch-misses # 0.363 % ( +- 0.258% )
1,067,367,848 branches # 712.673 M/sec ( +- 2.622% )
3,828,370,782 instructions # 0.947 IPC ( +- 0.033% )
4,043,832,831 cycles # 2700.037 M/sec ( +- 0.167% )
8,518 page-faults # 0.006 M/sec ( +- 3.648% )
847 CPU-migrations # 0.001 M/sec ( +- 3.262% )
6,546 context-switches # 0.004 M/sec ( +- 2.292% )
1497.695495 task-clock-msecs # 3.303 CPUs ( +- 2.550% )
0.453394396 seconds time elapsed ( +- 0.912% )
after:
$ perf stat --repeat=5 git grep qwerty > /dev/null
Performance counter stats for 'git grep qwerty' (5 runs):
2,989,918 cache-misses # 3.166 M/sec ( +- 5.013% )
10,986,041 cache-references # 11.633 M/sec ( +- 4.899% ) (scaled from 95.06%)
3,511,993 branch-misses # 1.422 % ( +- 0.785% )
246,893,561 branches # 261.433 M/sec ( +- 3.967% )
1,392,727,757 instructions # 0.564 IPC ( +- 0.040% )
2,468,142,397 cycles # 2613.494 M/sec ( +- 0.110% )
7,747 page-faults # 0.008 M/sec ( +- 3.995% )
897 CPU-migrations # 0.001 M/sec ( +- 2.383% )
6,535 context-switches # 0.007 M/sec ( +- 1.993% )
944.384228 task-clock-msecs # 3.177 CPUs ( +- 0.268% )
0.297257643 seconds time elapsed ( +- 0.450% )
So we gain about 35% by using the kwset code.
As a side effect of using kwset two grep tests are fixed by this
patch. The first is fixed because kwset can deal with case-insensitive
search containing NULs, something strcasestr cannot do. The second one
is fixed because we consider patterns containing NULs as fixed strings
(regcomp cannot accept patterns with NULs).
Signed-off-by: Fredrik Kuivinen <frekui@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-08-21 06:42:18 +08:00
|
|
|
kwset_t kws;
|
2009-01-10 07:18:34 +08:00
|
|
|
unsigned fixed:1;
|
2009-11-06 17:22:35 +08:00
|
|
|
unsigned ignore_case:1;
|
2009-03-07 20:28:40 +08:00
|
|
|
unsigned word_regexp:1;
|
2006-09-18 07:02:52 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
enum grep_expr_node {
|
|
|
|
GREP_NODE_ATOM,
|
|
|
|
GREP_NODE_NOT,
|
|
|
|
GREP_NODE_AND,
|
2010-09-13 13:15:35 +08:00
|
|
|
GREP_NODE_TRUE,
|
2010-05-14 17:31:35 +08:00
|
|
|
GREP_NODE_OR
|
2006-09-18 07:02:52 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct grep_expr {
|
|
|
|
enum grep_expr_node node;
|
2006-09-28 08:50:52 +08:00
|
|
|
unsigned hit;
|
2006-09-18 07:02:52 +08:00
|
|
|
union {
|
|
|
|
struct grep_pat *atom;
|
|
|
|
struct grep_expr *unary;
|
|
|
|
struct {
|
|
|
|
struct grep_expr *left;
|
|
|
|
struct grep_expr *right;
|
|
|
|
} binary;
|
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct grep_opt {
|
|
|
|
struct grep_pat *pattern_list;
|
|
|
|
struct grep_pat **pattern_tail;
|
"log --author=me --grep=it" should find intersection, not union
Historically, any grep filter in "git log" family of commands were taken
as restricting to commits with any of the words in the commit log message.
However, the user almost always want to find commits "done by this person
on that topic". With "--all-match" option, a series of grep patterns can
be turned into a requirement that all of them must produce a match, but
that makes it impossible to ask for "done by me, on either this or that"
with:
log --author=me --committer=him --grep=this --grep=that
because it will require both "this" and "that" to appear.
Change the "header" parser of grep library to treat the headers specially,
and parse it as:
(all-match-OR (HEADER-AUTHOR me)
(HEADER-COMMITTER him)
(OR
(PATTERN this)
(PATTERN that) ) )
Even though the "log" command line parser doesn't give direct access to
the extended grep syntax to group terms with parentheses, this change will
cover the majority of the case the users would want.
This incidentally revealed that one test in t7002 was bogus. It ran:
log --author=Thor --grep=Thu --format='%s'
and expected (wrongly) "Thu" to match "Thursday" in the author/committer
date, but that would never match, as the timestamp in raw commit buffer
does not have the name of the day-of-the-week.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-18 12:09:06 +08:00
|
|
|
struct grep_pat *header_list;
|
|
|
|
struct grep_pat **header_tail;
|
2006-09-18 07:02:52 +08:00
|
|
|
struct grep_expr *pattern_expression;
|
2009-09-05 20:31:17 +08:00
|
|
|
const char *prefix;
|
2006-09-18 07:02:52 +08:00
|
|
|
int prefix_length;
|
|
|
|
regex_t regexp;
|
2009-05-08 03:46:48 +08:00
|
|
|
int linenum;
|
|
|
|
int invert;
|
2009-11-06 17:22:35 +08:00
|
|
|
int ignore_case;
|
2009-05-08 03:46:48 +08:00
|
|
|
int status_only;
|
|
|
|
int name_only;
|
|
|
|
int unmatch_name_only;
|
|
|
|
int count;
|
|
|
|
int word_regexp;
|
|
|
|
int fixed;
|
|
|
|
int all_match;
|
2006-09-18 07:02:52 +08:00
|
|
|
#define GREP_BINARY_DEFAULT 0
|
|
|
|
#define GREP_BINARY_NOMATCH 1
|
|
|
|
#define GREP_BINARY_TEXT 2
|
2009-05-08 03:46:48 +08:00
|
|
|
int binary;
|
|
|
|
int extended;
|
2011-05-10 05:52:05 +08:00
|
|
|
int pcre;
|
2009-05-08 03:46:48 +08:00
|
|
|
int relative;
|
|
|
|
int pathname;
|
|
|
|
int null_following_name;
|
2009-03-07 20:32:32 +08:00
|
|
|
int color;
|
grep: Add --max-depth option.
It is useful to grep directories non-recursively, e.g. when one wants to
look for all files in the toplevel directory, but not in any subdirectory,
or in Documentation/, but not in Documentation/technical/.
This patch adds support for --max-depth <depth> option to git-grep. If it is
given, git-grep descends at most <depth> levels of directories below paths
specified on the command line.
Note that if path specified on command line contains wildcards, this option
makes no sense, e.g.
$ git grep -l --max-depth 0 GNU -- 'contrib/*'
(note the quotes) will search all files in contrib/, even in
subdirectories, because '*' matches all files.
Documentation updates, bash-completion and simple test cases are also
provided.
Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-07-23 01:52:15 +08:00
|
|
|
int max_depth;
|
2009-07-02 06:06:34 +08:00
|
|
|
int funcname;
|
2011-08-02 01:20:53 +08:00
|
|
|
int funcbody;
|
2010-03-08 00:52:47 +08:00
|
|
|
char color_context[COLOR_MAXLEN];
|
grep: Colorize filename, line number, and separator
Colorize the filename, line number, and separator in git grep output, as
GNU grep does. The colors are customizable through color.grep.<slot>.
The default is to only color the separator (in cyan), since this gives
the biggest legibility increase without overwhelming the user with
colors. GNU grep also defaults cyan for the separator, but defaults to
magenta for the filename and to green for the line number, as well.
There is one difference from GNU grep: When a binary file matches
without -a, GNU grep does not color the <file> in "Binary file <file>
matches", but we do.
Like GNU grep, if --null is given, the null separators are not colored.
For config.txt, use a a sub-list to describe the slots, rather than
a single paragraph with parentheses, since this is much more readable.
Remove the cast to int for `rm_eo - rm_so` since it is not necessary.
Signed-off-by: Mark Lodato <lodatom@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-03-08 00:52:46 +08:00
|
|
|
char color_filename[COLOR_MAXLEN];
|
2010-03-08 00:52:47 +08:00
|
|
|
char color_function[COLOR_MAXLEN];
|
grep: Colorize filename, line number, and separator
Colorize the filename, line number, and separator in git grep output, as
GNU grep does. The colors are customizable through color.grep.<slot>.
The default is to only color the separator (in cyan), since this gives
the biggest legibility increase without overwhelming the user with
colors. GNU grep also defaults cyan for the separator, but defaults to
magenta for the filename and to green for the line number, as well.
There is one difference from GNU grep: When a binary file matches
without -a, GNU grep does not color the <file> in "Binary file <file>
matches", but we do.
Like GNU grep, if --null is given, the null separators are not colored.
For config.txt, use a a sub-list to describe the slots, rather than
a single paragraph with parentheses, since this is much more readable.
Remove the cast to int for `rm_eo - rm_so` since it is not necessary.
Signed-off-by: Mark Lodato <lodatom@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-03-08 00:52:46 +08:00
|
|
|
char color_lineno[COLOR_MAXLEN];
|
2009-03-07 20:32:32 +08:00
|
|
|
char color_match[COLOR_MAXLEN];
|
2010-03-08 00:52:47 +08:00
|
|
|
char color_selected[COLOR_MAXLEN];
|
grep: Colorize filename, line number, and separator
Colorize the filename, line number, and separator in git grep output, as
GNU grep does. The colors are customizable through color.grep.<slot>.
The default is to only color the separator (in cyan), since this gives
the biggest legibility increase without overwhelming the user with
colors. GNU grep also defaults cyan for the separator, but defaults to
magenta for the filename and to green for the line number, as well.
There is one difference from GNU grep: When a binary file matches
without -a, GNU grep does not color the <file> in "Binary file <file>
matches", but we do.
Like GNU grep, if --null is given, the null separators are not colored.
For config.txt, use a a sub-list to describe the slots, rather than
a single paragraph with parentheses, since this is much more readable.
Remove the cast to int for `rm_eo - rm_so` since it is not necessary.
Signed-off-by: Mark Lodato <lodatom@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-03-08 00:52:46 +08:00
|
|
|
char color_sep[COLOR_MAXLEN];
|
2006-09-18 07:02:52 +08:00
|
|
|
int regflags;
|
|
|
|
unsigned pre_context;
|
|
|
|
unsigned post_context;
|
2009-07-02 06:02:38 +08:00
|
|
|
unsigned last_shown;
|
2009-07-02 06:03:44 +08:00
|
|
|
int show_hunk_mark;
|
2011-06-05 23:24:25 +08:00
|
|
|
int file_break;
|
2011-06-05 23:24:36 +08:00
|
|
|
int heading;
|
2009-07-02 06:07:24 +08:00
|
|
|
void *priv;
|
2010-01-26 06:51:39 +08:00
|
|
|
|
|
|
|
void (*output)(struct grep_opt *opt, const void *data, size_t size);
|
|
|
|
void *output_priv;
|
2006-09-18 07:02:52 +08:00
|
|
|
};
|
|
|
|
|
2010-05-23 05:43:43 +08:00
|
|
|
extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
|
2006-09-18 07:02:52 +08:00
|
|
|
extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
|
log --author/--committer: really match only with name part
When we tried to find commits done by AUTHOR, the first implementation
tried to pattern match a line with "^author .*AUTHOR", which later was
enhanced to strip leading caret and look for "^author AUTHOR" when the
search pattern was anchored at the left end (i.e. --author="^AUTHOR").
This had a few problems:
* When looking for fixed strings (e.g. "git log -F --author=x --grep=y"),
the regexp internally used "^author .*x" would never match anything;
* To match at the end (e.g. "git log --author='google.com>$'"), the
generated regexp has to also match the trailing timestamp part the
commit header lines have. Also, in order to determine if the '$' at
the end means "match at the end of the line" or just a literal dollar
sign (probably backslash-quoted), we would need to parse the regexp
ourselves.
An earlier alternative tried to make sure that a line matches "^author "
(to limit by field name) and the user supplied pattern at the same time.
While it solved the -F problem by introducing a special override for
matching the "^author ", it did not solve the trailing timestamp nor tail
match problem. It also would have matched every commit if --author=author
was asked for, not because the author's email part had this string, but
because every commit header line that talks about the author begins with
that field name, regardleses of who wrote it.
Instead of piling more hacks on top of hacks, this rethinks the grep
machinery that is used to look for strings in the commit header, and makes
sure that (1) field name matches literally at the beginning of the line,
followed by a SP, and (2) the user supplied pattern is matched against the
remainder of the line, excluding the trailing timestamp data.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
|
|
|
extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
|
2006-09-18 07:02:52 +08:00
|
|
|
extern void compile_grep_patterns(struct grep_opt *opt);
|
2006-09-28 07:27:10 +08:00
|
|
|
extern void free_grep_patterns(struct grep_opt *opt);
|
2012-02-02 16:20:10 +08:00
|
|
|
extern int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size);
|
2006-09-18 07:02:52 +08:00
|
|
|
|
grep: refactor the concept of "grep source" into an object
The main interface to the low-level grep code is
grep_buffer, which takes a pointer to a buffer and a size.
This is convenient and flexible (we use it to grep commit
bodies, files on disk, and blobs by sha1), but it makes it
hard to pass extra information about what we are grepping
(either for correctness, like overriding binary
auto-detection, or for optimizations, like lazily loading
blob contents).
Instead, let's encapsulate the idea of a "grep source",
including the buffer, its size, and where the data is coming
from. This is similar to the diff_filespec structure used by
the diff code (unsurprising, since future patches will
implement some of the same optimizations found there).
The diffstat is slightly scarier than the actual patch
content. Most of the modified lines are simply replacing
access to raw variables with their counterparts that are now
in a "struct grep_source". Most of the added lines were
taken from builtin/grep.c, which partially abstracted the
idea of grep sources (for file vs sha1 sources).
Instead of dropping the now-redundant code, this patch
leaves builtin/grep.c using the traditional grep_buffer
interface (which now wraps the grep_source interface). That
makes it easy to test that there is no change of behavior
(yet).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-02 16:19:28 +08:00
|
|
|
struct grep_source {
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
enum grep_source_type {
|
|
|
|
GREP_SOURCE_SHA1,
|
|
|
|
GREP_SOURCE_FILE,
|
|
|
|
GREP_SOURCE_BUF,
|
|
|
|
} type;
|
|
|
|
void *identifier;
|
|
|
|
|
|
|
|
char *buf;
|
|
|
|
unsigned long size;
|
|
|
|
};
|
|
|
|
|
|
|
|
void grep_source_init(struct grep_source *gs, enum grep_source_type type,
|
|
|
|
const char *name, const void *identifier);
|
|
|
|
int grep_source_load(struct grep_source *gs);
|
|
|
|
void grep_source_clear_data(struct grep_source *gs);
|
|
|
|
void grep_source_clear(struct grep_source *gs);
|
|
|
|
|
|
|
|
int grep_source(struct grep_opt *opt, struct grep_source *gs);
|
|
|
|
|
2010-01-26 06:51:39 +08:00
|
|
|
extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt);
|
|
|
|
extern int grep_threads_ok(const struct grep_opt *opt);
|
|
|
|
|
2011-12-13 05:16:07 +08:00
|
|
|
#ifndef NO_PTHREADS
|
|
|
|
/*
|
|
|
|
* Mutex used around access to the attributes machinery if
|
|
|
|
* opt->use_threads. Must be initialized/destroyed by callers!
|
|
|
|
*/
|
grep: make locking flag global
The low-level grep code traditionally didn't care about
threading, as it doesn't do any threading itself and didn't
call out to other non-thread-safe code. That changed with
0579f91 (grep: enable threading with -p and -W using lazy
attribute lookup, 2011-12-12), which pushed the lookup of
funcname attributes (which is not thread-safe) into the
low-level grep code.
As a result, the low-level code learned about a new global
"grep_attr_mutex" to serialize access to the attribute code.
A multi-threaded caller (e.g., builtin/grep.c) is expected
to initialize the mutex and set "use_threads" in the
grep_opt structure. The low-level code only uses the lock if
use_threads is set.
However, putting the use_threads flag into the grep_opt
struct is not the most logical place. Whether threading is
in use is not something that matters for each call to
grep_buffer, but is instead global to the whole program
(i.e., if any thread is doing multi-threaded grep, every
other thread, even if it thinks it is doing its own
single-threaded grep, would need to use the locking). In
practice, this distinction isn't a problem for us, because
the only user of multi-threaded grep is "git-grep", which
does nothing except call grep.
This patch turns the opt->use_threads flag into a global
flag. More important than the nit-picking semantic argument
above is that this means that the locking functions don't
need to actually have access to a grep_opt to know whether
to lock. Which in turn can make adding new locks simpler, as
we don't need to pass around a grep_opt.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-02 16:18:29 +08:00
|
|
|
extern int grep_use_locks;
|
2011-12-13 05:16:07 +08:00
|
|
|
extern pthread_mutex_t grep_attr_mutex;
|
2012-02-02 16:18:41 +08:00
|
|
|
extern pthread_mutex_t grep_read_mutex;
|
|
|
|
|
|
|
|
static inline void grep_read_lock(void)
|
|
|
|
{
|
|
|
|
if (grep_use_locks)
|
|
|
|
pthread_mutex_lock(&grep_read_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void grep_read_unlock(void)
|
|
|
|
{
|
|
|
|
if (grep_use_locks)
|
|
|
|
pthread_mutex_unlock(&grep_read_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#define grep_read_lock()
|
|
|
|
#define grep_read_unlock()
|
2011-12-13 05:16:07 +08:00
|
|
|
#endif
|
|
|
|
|
2006-09-18 07:02:52 +08:00
|
|
|
#endif
|