2006-05-01 08:28:15 +02:00
|
|
|
/*
|
|
|
|
* Builtin "git grep"
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006 Junio C Hamano
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
|
|
|
#include "blob.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "commit.h"
|
|
|
|
#include "tag.h"
|
2006-05-02 00:58:29 +02:00
|
|
|
#include "tree-walk.h"
|
2006-05-01 08:28:15 +02:00
|
|
|
#include "builtin.h"
|
2009-05-07 21:46:48 +02:00
|
|
|
#include "parse-options.h"
|
2010-06-12 18:36:51 +02:00
|
|
|
#include "string-list.h"
|
|
|
|
#include "run-command.h"
|
2009-07-02 00:07:24 +02:00
|
|
|
#include "userdiff.h"
|
2006-09-18 01:02:52 +02:00
|
|
|
#include "grep.h"
|
2009-09-05 14:31:17 +02:00
|
|
|
#include "quote.h"
|
2010-02-06 19:40:08 +01:00
|
|
|
#include "dir.h"
|
2010-01-25 23:51:39 +01:00
|
|
|
|
2009-05-07 21:46:48 +02:00
|
|
|
static char const * const grep_usage[] = {
|
2010-10-08 19:31:15 +02:00
|
|
|
"git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
|
2009-05-07 21:46:48 +02:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2010-01-25 23:51:39 +01:00
|
|
|
static int use_threads = 1;
|
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
|
|
|
#define THREADS 8
|
|
|
|
static pthread_t threads[THREADS];
|
|
|
|
|
|
|
|
/* We use one producer thread and THREADS consumer
|
|
|
|
* threads. The producer adds struct work_items to 'todo' and the
|
|
|
|
* consumers pick work items from the same array.
|
|
|
|
*/
|
2011-03-16 08:08:34 +01:00
|
|
|
struct work_item {
|
2012-02-02 09:19:37 +01:00
|
|
|
struct grep_source source;
|
2010-01-25 23:51:39 +01:00
|
|
|
char done;
|
|
|
|
struct strbuf out;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* In the range [todo_done, todo_start) in 'todo' we have work_items
|
|
|
|
* that have been or are processed by a consumer thread. We haven't
|
|
|
|
* written the result for these to stdout yet.
|
|
|
|
*
|
|
|
|
* The work_items in [todo_start, todo_end) are waiting to be picked
|
|
|
|
* up by a consumer thread.
|
|
|
|
*
|
|
|
|
* The ranges are modulo TODO_SIZE.
|
|
|
|
*/
|
|
|
|
#define TODO_SIZE 128
|
|
|
|
static struct work_item todo[TODO_SIZE];
|
|
|
|
static int todo_start;
|
|
|
|
static int todo_end;
|
|
|
|
static int todo_done;
|
|
|
|
|
|
|
|
/* Has all work items been added? */
|
|
|
|
static int all_work_added;
|
|
|
|
|
|
|
|
/* This lock protects all the variables above. */
|
|
|
|
static pthread_mutex_t grep_mutex;
|
|
|
|
|
2011-10-26 20:45:15 +02:00
|
|
|
static inline void grep_lock(void)
|
|
|
|
{
|
|
|
|
if (use_threads)
|
|
|
|
pthread_mutex_lock(&grep_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void grep_unlock(void)
|
|
|
|
{
|
|
|
|
if (use_threads)
|
|
|
|
pthread_mutex_unlock(&grep_mutex);
|
|
|
|
}
|
|
|
|
|
2010-01-25 23:51:39 +01:00
|
|
|
/* Signalled when a new work_item is added to todo. */
|
|
|
|
static pthread_cond_t cond_add;
|
|
|
|
|
|
|
|
/* Signalled when the result from one work_item is written to
|
|
|
|
* stdout.
|
|
|
|
*/
|
|
|
|
static pthread_cond_t cond_write;
|
|
|
|
|
|
|
|
/* Signalled when we are finished with everything. */
|
|
|
|
static pthread_cond_t cond_result;
|
|
|
|
|
2011-06-05 17:24:15 +02:00
|
|
|
static int skip_first_line;
|
2010-03-15 17:21:10 +01:00
|
|
|
|
2012-02-02 09:24:28 +01:00
|
|
|
static void add_work(struct grep_opt *opt, enum grep_source_type type,
|
|
|
|
const char *name, const void *id)
|
2010-01-25 23:51:39 +01:00
|
|
|
{
|
|
|
|
grep_lock();
|
|
|
|
|
|
|
|
while ((todo_end+1) % ARRAY_SIZE(todo) == todo_done) {
|
|
|
|
pthread_cond_wait(&cond_write, &grep_mutex);
|
|
|
|
}
|
|
|
|
|
2012-02-02 09:19:37 +01:00
|
|
|
grep_source_init(&todo[todo_end].source, type, name, id);
|
2012-02-02 09:24:28 +01:00
|
|
|
if (opt->binary != GREP_BINARY_TEXT)
|
|
|
|
grep_source_load_driver(&todo[todo_end].source);
|
2010-01-25 23:51:39 +01:00
|
|
|
todo[todo_end].done = 0;
|
|
|
|
strbuf_reset(&todo[todo_end].out);
|
|
|
|
todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
|
|
|
|
|
|
|
|
pthread_cond_signal(&cond_add);
|
|
|
|
grep_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct work_item *get_work(void)
|
|
|
|
{
|
|
|
|
struct work_item *ret;
|
|
|
|
|
|
|
|
grep_lock();
|
|
|
|
while (todo_start == todo_end && !all_work_added) {
|
|
|
|
pthread_cond_wait(&cond_add, &grep_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (todo_start == todo_end && all_work_added) {
|
|
|
|
ret = NULL;
|
|
|
|
} else {
|
|
|
|
ret = &todo[todo_start];
|
|
|
|
todo_start = (todo_start + 1) % ARRAY_SIZE(todo);
|
|
|
|
}
|
|
|
|
grep_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void work_done(struct work_item *w)
|
|
|
|
{
|
|
|
|
int old_done;
|
|
|
|
|
|
|
|
grep_lock();
|
|
|
|
w->done = 1;
|
|
|
|
old_done = todo_done;
|
|
|
|
for(; todo[todo_done].done && todo_done != todo_start;
|
|
|
|
todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
|
|
|
|
w = &todo[todo_done];
|
2010-03-15 17:21:10 +01:00
|
|
|
if (w->out.len) {
|
2011-06-05 17:24:15 +02:00
|
|
|
const char *p = w->out.buf;
|
|
|
|
size_t len = w->out.len;
|
|
|
|
|
|
|
|
/* Skip the leading hunk mark of the first file. */
|
|
|
|
if (skip_first_line) {
|
|
|
|
while (len) {
|
|
|
|
len--;
|
|
|
|
if (*p++ == '\n')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
skip_first_line = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
write_or_die(1, p, len);
|
2010-03-15 17:21:10 +01:00
|
|
|
}
|
2012-02-02 09:19:37 +01:00
|
|
|
grep_source_clear(&w->source);
|
2010-01-25 23:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (old_done != todo_done)
|
|
|
|
pthread_cond_signal(&cond_write);
|
|
|
|
|
|
|
|
if (all_work_added && todo_done == todo_end)
|
|
|
|
pthread_cond_signal(&cond_result);
|
|
|
|
|
|
|
|
grep_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *run(void *arg)
|
|
|
|
{
|
|
|
|
int hit = 0;
|
|
|
|
struct grep_opt *opt = arg;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct work_item *w = get_work();
|
|
|
|
if (!w)
|
|
|
|
break;
|
|
|
|
|
|
|
|
opt->output_priv = w;
|
2012-02-02 09:19:37 +01:00
|
|
|
hit |= grep_source(opt, &w->source);
|
|
|
|
grep_source_clear_data(&w->source);
|
2010-01-25 23:51:39 +01:00
|
|
|
work_done(w);
|
|
|
|
}
|
2010-01-30 16:42:58 +01:00
|
|
|
free_grep_patterns(arg);
|
|
|
|
free(arg);
|
2010-01-25 23:51:39 +01:00
|
|
|
|
|
|
|
return (void*) (intptr_t) hit;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void strbuf_out(struct grep_opt *opt, const void *buf, size_t size)
|
|
|
|
{
|
|
|
|
struct work_item *w = opt->output_priv;
|
|
|
|
strbuf_add(&w->out, buf, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void start_threads(struct grep_opt *opt)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
pthread_mutex_init(&grep_mutex, NULL);
|
2012-02-02 09:18:41 +01:00
|
|
|
pthread_mutex_init(&grep_read_mutex, NULL);
|
2011-12-12 22:16:07 +01:00
|
|
|
pthread_mutex_init(&grep_attr_mutex, NULL);
|
2010-01-25 23:51:39 +01:00
|
|
|
pthread_cond_init(&cond_add, NULL);
|
|
|
|
pthread_cond_init(&cond_write, NULL);
|
|
|
|
pthread_cond_init(&cond_result, NULL);
|
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 09:18:29 +01:00
|
|
|
grep_use_locks = 1;
|
2010-01-25 23:51:39 +01:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(todo); i++) {
|
|
|
|
strbuf_init(&todo[i].out, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(threads); i++) {
|
|
|
|
int err;
|
|
|
|
struct grep_opt *o = grep_opt_dup(opt);
|
|
|
|
o->output = strbuf_out;
|
|
|
|
compile_grep_patterns(o);
|
|
|
|
err = pthread_create(&threads[i], NULL, run, o);
|
|
|
|
|
|
|
|
if (err)
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("grep: failed to create thread: %s"),
|
2010-01-25 23:51:39 +01:00
|
|
|
strerror(err));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wait_all(void)
|
|
|
|
{
|
|
|
|
int hit = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
grep_lock();
|
|
|
|
all_work_added = 1;
|
|
|
|
|
|
|
|
/* Wait until all work is done. */
|
|
|
|
while (todo_done != todo_end)
|
|
|
|
pthread_cond_wait(&cond_result, &grep_mutex);
|
|
|
|
|
|
|
|
/* Wake up all the consumer threads so they can see that there
|
|
|
|
* is no more work to do.
|
|
|
|
*/
|
|
|
|
pthread_cond_broadcast(&cond_add);
|
|
|
|
grep_unlock();
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(threads); i++) {
|
|
|
|
void *h;
|
|
|
|
pthread_join(threads[i], &h);
|
|
|
|
hit |= (int) (intptr_t) h;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_destroy(&grep_mutex);
|
2012-02-02 09:18:41 +01:00
|
|
|
pthread_mutex_destroy(&grep_read_mutex);
|
2011-12-12 22:16:07 +01:00
|
|
|
pthread_mutex_destroy(&grep_attr_mutex);
|
2010-01-25 23:51:39 +01:00
|
|
|
pthread_cond_destroy(&cond_add);
|
|
|
|
pthread_cond_destroy(&cond_write);
|
|
|
|
pthread_cond_destroy(&cond_result);
|
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 09:18:29 +01:00
|
|
|
grep_use_locks = 0;
|
2010-01-25 23:51:39 +01:00
|
|
|
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
#else /* !NO_PTHREADS */
|
|
|
|
|
|
|
|
static int wait_all(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-03-07 13:32:32 +01:00
|
|
|
static int grep_config(const char *var, const char *value, void *cb)
|
|
|
|
{
|
|
|
|
struct grep_opt *opt = cb;
|
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-07 17:52:46 +01:00
|
|
|
char *color = NULL;
|
2009-03-07 13:32:32 +01:00
|
|
|
|
drop odd return value semantics from userdiff_config
When the userdiff_config function was introduced in be58e70
(diff: unify external diff and funcname parsing code,
2008-10-05), it used a return value convention unlike any
other config callback. Like other callbacks, it used "-1" to
signal error. But it returned "1" to indicate that it found
something, and "0" otherwise; other callbacks simply
returned "0" to indicate that no error occurred.
This distinction was necessary at the time, because the
userdiff namespace overlapped slightly with the color
configuration namespace. So "diff.color.foo" could mean "the
'foo' slot of diff coloring" or "the 'foo' component of the
"color" userdiff driver". Because the color-parsing code
would die on an unknown color slot, we needed the userdiff
code to indicate that it had matched the variable, letting
us bypass the color-parsing code entirely.
Later, in 8b8e862 (ignore unknown color configuration,
2009-12-12), the color-parsing code learned to silently
ignore unknown slots. This means we no longer need to
protect userdiff-matched variables from reaching the
color-parsing code.
We can therefore change the userdiff_config calling
convention to a more normal one. This drops some code from
each caller, which is nice. But more importantly, it reduces
the cognitive load for readers who may wonder why
userdiff_config is unlike every other config callback.
There's no need to add a new test confirming that this
works; t4020 already contains a test that sets
diff.color.external.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-07 19:23:02 +01:00
|
|
|
if (userdiff_config(var, value) < 0)
|
|
|
|
return -1;
|
2009-07-02 00:07:24 +02:00
|
|
|
|
2011-03-30 21:31:05 +02:00
|
|
|
if (!strcmp(var, "grep.extendedregexp")) {
|
|
|
|
if (git_config_bool(var, value))
|
|
|
|
opt->regflags |= REG_EXTENDED;
|
|
|
|
else
|
|
|
|
opt->regflags &= ~REG_EXTENDED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(var, "grep.linenumber")) {
|
|
|
|
opt->linenum = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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-07 17:52:46 +01:00
|
|
|
if (!strcmp(var, "color.grep"))
|
2011-08-18 07:03:48 +02:00
|
|
|
opt->color = git_config_colorbool(var, value);
|
2010-03-07 17:52:47 +01:00
|
|
|
else if (!strcmp(var, "color.grep.context"))
|
|
|
|
color = opt->color_context;
|
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-07 17:52:46 +01:00
|
|
|
else if (!strcmp(var, "color.grep.filename"))
|
|
|
|
color = opt->color_filename;
|
2010-03-07 17:52:47 +01:00
|
|
|
else if (!strcmp(var, "color.grep.function"))
|
|
|
|
color = opt->color_function;
|
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-07 17:52:46 +01:00
|
|
|
else if (!strcmp(var, "color.grep.linenumber"))
|
|
|
|
color = opt->color_lineno;
|
|
|
|
else if (!strcmp(var, "color.grep.match"))
|
|
|
|
color = opt->color_match;
|
2010-03-07 17:52:47 +01:00
|
|
|
else if (!strcmp(var, "color.grep.selected"))
|
|
|
|
color = opt->color_selected;
|
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-07 17:52:46 +01:00
|
|
|
else if (!strcmp(var, "color.grep.separator"))
|
|
|
|
color = opt->color_sep;
|
|
|
|
else
|
|
|
|
return git_color_default_config(var, value, cb);
|
|
|
|
if (color) {
|
2009-03-07 13:32:32 +01:00
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
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-07 17:52:46 +01:00
|
|
|
color_parse(value, var, color);
|
2009-03-07 13:32:32 +01:00
|
|
|
}
|
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-07 17:52:46 +01:00
|
|
|
return 0;
|
2009-03-07 13:32:32 +01:00
|
|
|
}
|
|
|
|
|
2010-02-16 03:34:28 +01:00
|
|
|
static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
|
|
|
|
{
|
|
|
|
void *data;
|
|
|
|
|
2012-02-02 09:18:41 +01:00
|
|
|
grep_read_lock();
|
2011-10-26 21:15:51 +02:00
|
|
|
data = read_sha1_file(sha1, type, size);
|
2012-02-02 09:18:41 +01:00
|
|
|
grep_read_unlock();
|
2010-01-25 23:51:39 +01:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
|
|
|
|
const char *filename, int tree_name_len)
|
|
|
|
{
|
|
|
|
struct strbuf pathbuf = STRBUF_INIT;
|
|
|
|
|
2006-08-11 09:44:42 +02:00
|
|
|
if (opt->relative && opt->prefix_length) {
|
2010-01-25 23:51:39 +01:00
|
|
|
quote_path_relative(filename + tree_name_len, -1, &pathbuf,
|
|
|
|
opt->prefix);
|
|
|
|
strbuf_insert(&pathbuf, 0, filename, tree_name_len);
|
|
|
|
} else {
|
|
|
|
strbuf_addstr(&pathbuf, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
|
|
|
if (use_threads) {
|
2012-02-02 09:24:28 +01:00
|
|
|
add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
|
2012-02-02 09:19:37 +01:00
|
|
|
strbuf_release(&pathbuf);
|
2010-01-25 23:51:39 +01:00
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2012-02-02 09:19:37 +01:00
|
|
|
struct grep_source gs;
|
2010-01-25 23:51:39 +01:00
|
|
|
int hit;
|
2006-05-01 08:28:15 +02:00
|
|
|
|
2012-02-02 09:19:37 +01:00
|
|
|
grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
|
|
|
|
strbuf_release(&pathbuf);
|
|
|
|
hit = grep_source(opt, &gs);
|
2007-03-07 02:44:37 +01:00
|
|
|
|
2012-02-02 09:19:37 +01:00
|
|
|
grep_source_clear(&gs);
|
|
|
|
return hit;
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
2010-01-25 23:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int grep_file(struct grep_opt *opt, const char *filename)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
2006-08-11 09:44:42 +02:00
|
|
|
if (opt->relative && opt->prefix_length)
|
2010-01-25 23:51:39 +01:00
|
|
|
quote_path_relative(filename, -1, &buf, opt->prefix);
|
|
|
|
else
|
|
|
|
strbuf_addstr(&buf, filename);
|
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
|
|
|
if (use_threads) {
|
2012-02-02 09:24:28 +01:00
|
|
|
add_work(opt, GREP_SOURCE_FILE, buf.buf, filename);
|
2012-02-02 09:19:37 +01:00
|
|
|
strbuf_release(&buf);
|
2010-01-25 23:51:39 +01:00
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2012-02-02 09:19:37 +01:00
|
|
|
struct grep_source gs;
|
2010-01-25 23:51:39 +01:00
|
|
|
int hit;
|
|
|
|
|
2012-02-02 09:19:37 +01:00
|
|
|
grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
hit = grep_source(opt, &gs);
|
|
|
|
|
|
|
|
grep_source_clear(&gs);
|
2010-01-25 23:51:39 +01:00
|
|
|
return hit;
|
|
|
|
}
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
|
|
|
|
2010-06-12 18:36:51 +02:00
|
|
|
static void append_path(struct grep_opt *opt, const void *data, size_t len)
|
|
|
|
{
|
|
|
|
struct string_list *path_list = opt->output_priv;
|
|
|
|
|
|
|
|
if (len == 1 && *(const char *)data == '\0')
|
|
|
|
return;
|
2010-06-26 01:41:39 +02:00
|
|
|
string_list_append(path_list, xstrndup(data, len));
|
2010-06-12 18:36:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void run_pager(struct grep_opt *opt, const char *prefix)
|
|
|
|
{
|
|
|
|
struct string_list *path_list = opt->output_priv;
|
|
|
|
const char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));
|
|
|
|
int i, status;
|
|
|
|
|
|
|
|
for (i = 0; i < path_list->nr; i++)
|
|
|
|
argv[i] = path_list->items[i].string;
|
|
|
|
argv[path_list->nr] = NULL;
|
|
|
|
|
|
|
|
if (prefix && chdir(prefix))
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("Failed to chdir: %s"), prefix);
|
2010-06-12 18:36:51 +02:00
|
|
|
status = run_command_v_opt(argv, RUN_USING_SHELL);
|
|
|
|
if (status)
|
|
|
|
exit(status);
|
|
|
|
free(argv);
|
|
|
|
}
|
|
|
|
|
2010-12-15 16:02:51 +01:00
|
|
|
static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
|
2006-05-01 08:28:15 +02:00
|
|
|
{
|
|
|
|
int hit = 0;
|
|
|
|
int nr;
|
|
|
|
read_cache();
|
|
|
|
|
|
|
|
for (nr = 0; nr < active_nr; nr++) {
|
|
|
|
struct cache_entry *ce = active_cache[nr];
|
2008-01-15 01:03:17 +01:00
|
|
|
if (!S_ISREG(ce->ce_mode))
|
2006-05-01 08:28:15 +02:00
|
|
|
continue;
|
2010-12-15 16:02:52 +01:00
|
|
|
if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
|
2006-05-01 08:28:15 +02:00
|
|
|
continue;
|
2008-12-27 09:21:03 +01:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
2009-08-20 15:46:58 +02:00
|
|
|
if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
|
2006-11-26 21:47:52 +01:00
|
|
|
if (ce_stage(ce))
|
|
|
|
continue;
|
2006-08-11 09:44:42 +02:00
|
|
|
hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
|
2006-11-26 21:47:52 +01:00
|
|
|
}
|
2006-05-01 08:28:15 +02:00
|
|
|
else
|
|
|
|
hit |= grep_file(opt, ce->name);
|
2006-11-26 21:47:52 +01:00
|
|
|
if (ce_stage(ce)) {
|
|
|
|
do {
|
|
|
|
nr++;
|
|
|
|
} while (nr < active_nr &&
|
|
|
|
!strcmp(ce->name, active_cache[nr]->name));
|
|
|
|
nr--; /* compensate for loop control */
|
|
|
|
}
|
2010-01-26 00:37:23 +01:00
|
|
|
if (hit && opt->status_only)
|
|
|
|
break;
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2010-12-15 16:02:51 +01:00
|
|
|
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
|
2010-12-17 13:44:25 +01:00
|
|
|
struct tree_desc *tree, struct strbuf *base, int tn_len)
|
2006-05-01 08:28:15 +02:00
|
|
|
{
|
2011-10-24 08:36:10 +02:00
|
|
|
int hit = 0;
|
|
|
|
enum interesting match = entry_not_interesting;
|
tree_entry(): new tree-walking helper function
This adds a "tree_entry()" function that combines the common operation of
doing a "tree_entry_extract()" + "update_tree_entry()".
It also has a simplified calling convention, designed for simple loops
that traverse over a whole tree: the arguments are pointers to the tree
descriptor and a name_entry structure to fill in, and it returns a boolean
"true" if there was an entry left to be gotten in the tree.
This allows tree traversal with
struct tree_desc desc;
struct name_entry entry;
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry) {
... use "entry.{path, sha1, mode, pathlen}" ...
}
which is not only shorter than writing it out in full, it's hopefully less
error prone too.
[ It's actually a tad faster too - we don't need to recalculate the entry
pathlength in both extract and update, but need to do it only once.
Also, some callers can avoid doing a "strlen()" on the result, since
it's returned as part of the name_entry structure.
However, by now we're talking just 1% speedup on "git-rev-list --objects
--all", and we're definitely at the point where tree walking is no
longer the issue any more. ]
NOTE! Not everybody wants to use this new helper function, since some of
the tree walkers very much on purpose do the descriptor update separately
from the entry extraction. So the "extract + update" sequence still
remains as the core sequence, this is just a simplified interface.
We should probably add a silly two-line inline helper function for
initializing the descriptor from the "struct tree" too, just to cut down
on the noise from that common "desc" initializer.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-30 18:45:45 +02:00
|
|
|
struct name_entry entry;
|
2010-12-17 13:44:25 +01:00
|
|
|
int old_baselen = base->len;
|
2006-05-01 08:28:15 +02:00
|
|
|
|
tree_entry(): new tree-walking helper function
This adds a "tree_entry()" function that combines the common operation of
doing a "tree_entry_extract()" + "update_tree_entry()".
It also has a simplified calling convention, designed for simple loops
that traverse over a whole tree: the arguments are pointers to the tree
descriptor and a name_entry structure to fill in, and it returns a boolean
"true" if there was an entry left to be gotten in the tree.
This allows tree traversal with
struct tree_desc desc;
struct name_entry entry;
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry) {
... use "entry.{path, sha1, mode, pathlen}" ...
}
which is not only shorter than writing it out in full, it's hopefully less
error prone too.
[ It's actually a tad faster too - we don't need to recalculate the entry
pathlength in both extract and update, but need to do it only once.
Also, some callers can avoid doing a "strlen()" on the result, since
it's returned as part of the name_entry structure.
However, by now we're talking just 1% speedup on "git-rev-list --objects
--all", and we're definitely at the point where tree walking is no
longer the issue any more. ]
NOTE! Not everybody wants to use this new helper function, since some of
the tree walkers very much on purpose do the descriptor update separately
from the entry extraction. So the "extract + update" sequence still
remains as the core sequence, this is just a simplified interface.
We should probably add a silly two-line inline helper function for
initializing the descriptor from the "struct tree" too, just to cut down
on the noise from that common "desc" initializer.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-30 18:45:45 +02:00
|
|
|
while (tree_entry(tree, &entry)) {
|
2011-10-24 08:36:09 +02:00
|
|
|
int te_len = tree_entry_len(&entry);
|
2010-12-17 13:44:25 +01:00
|
|
|
|
2011-10-24 08:36:10 +02:00
|
|
|
if (match != all_entries_interesting) {
|
2011-03-25 10:34:20 +01:00
|
|
|
match = tree_entry_interesting(&entry, base, tn_len, pathspec);
|
2011-10-24 08:36:10 +02:00
|
|
|
if (match == all_entries_not_interesting)
|
2011-03-25 10:34:20 +01:00
|
|
|
break;
|
2011-10-24 08:36:10 +02:00
|
|
|
if (match == entry_not_interesting)
|
2010-12-17 13:45:33 +01:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-01 08:28:15 +02:00
|
|
|
|
2010-12-17 13:45:33 +01:00
|
|
|
strbuf_add(base, entry.path, te_len);
|
2006-05-01 21:27:56 +02:00
|
|
|
|
2010-12-17 13:45:33 +01:00
|
|
|
if (S_ISREG(entry.mode)) {
|
2010-12-17 13:44:25 +01:00
|
|
|
hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
|
|
|
|
}
|
tree_entry(): new tree-walking helper function
This adds a "tree_entry()" function that combines the common operation of
doing a "tree_entry_extract()" + "update_tree_entry()".
It also has a simplified calling convention, designed for simple loops
that traverse over a whole tree: the arguments are pointers to the tree
descriptor and a name_entry structure to fill in, and it returns a boolean
"true" if there was an entry left to be gotten in the tree.
This allows tree traversal with
struct tree_desc desc;
struct name_entry entry;
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry) {
... use "entry.{path, sha1, mode, pathlen}" ...
}
which is not only shorter than writing it out in full, it's hopefully less
error prone too.
[ It's actually a tad faster too - we don't need to recalculate the entry
pathlength in both extract and update, but need to do it only once.
Also, some callers can avoid doing a "strlen()" on the result, since
it's returned as part of the name_entry structure.
However, by now we're talking just 1% speedup on "git-rev-list --objects
--all", and we're definitely at the point where tree walking is no
longer the issue any more. ]
NOTE! Not everybody wants to use this new helper function, since some of
the tree walkers very much on purpose do the descriptor update separately
from the entry extraction. So the "extract + update" sequence still
remains as the core sequence, this is just a simplified interface.
We should probably add a silly two-line inline helper function for
initializing the descriptor from the "struct tree" too, just to cut down
on the noise from that common "desc" initializer.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-30 18:45:45 +02:00
|
|
|
else if (S_ISDIR(entry.mode)) {
|
2007-02-26 20:55:59 +01:00
|
|
|
enum object_type type;
|
2006-05-01 08:28:15 +02:00
|
|
|
struct tree_desc sub;
|
|
|
|
void *data;
|
2007-03-21 18:08:25 +01:00
|
|
|
unsigned long size;
|
|
|
|
|
2010-02-16 03:34:28 +01:00
|
|
|
data = lock_and_read_sha1_file(entry.sha1, &type, &size);
|
2006-05-01 08:28:15 +02:00
|
|
|
if (!data)
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("unable to read tree (%s)"),
|
tree_entry(): new tree-walking helper function
This adds a "tree_entry()" function that combines the common operation of
doing a "tree_entry_extract()" + "update_tree_entry()".
It also has a simplified calling convention, designed for simple loops
that traverse over a whole tree: the arguments are pointers to the tree
descriptor and a name_entry structure to fill in, and it returns a boolean
"true" if there was an entry left to be gotten in the tree.
This allows tree traversal with
struct tree_desc desc;
struct name_entry entry;
desc.buf = tree->buffer;
desc.size = tree->size;
while (tree_entry(&desc, &entry) {
... use "entry.{path, sha1, mode, pathlen}" ...
}
which is not only shorter than writing it out in full, it's hopefully less
error prone too.
[ It's actually a tad faster too - we don't need to recalculate the entry
pathlength in both extract and update, but need to do it only once.
Also, some callers can avoid doing a "strlen()" on the result, since
it's returned as part of the name_entry structure.
However, by now we're talking just 1% speedup on "git-rev-list --objects
--all", and we're definitely at the point where tree walking is no
longer the issue any more. ]
NOTE! Not everybody wants to use this new helper function, since some of
the tree walkers very much on purpose do the descriptor update separately
from the entry extraction. So the "extract + update" sequence still
remains as the core sequence, this is just a simplified interface.
We should probably add a silly two-line inline helper function for
initializing the descriptor from the "struct tree" too, just to cut down
on the noise from that common "desc" initializer.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-30 18:45:45 +02:00
|
|
|
sha1_to_hex(entry.sha1));
|
2010-12-17 13:45:33 +01:00
|
|
|
|
|
|
|
strbuf_addch(base, '/');
|
2007-03-21 18:08:25 +01:00
|
|
|
init_tree_desc(&sub, data, size);
|
2010-12-17 13:44:25 +01:00
|
|
|
hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
|
2006-05-01 08:28:15 +02:00
|
|
|
free(data);
|
|
|
|
}
|
2010-12-17 13:44:25 +01:00
|
|
|
strbuf_setlen(base, old_baselen);
|
|
|
|
|
2010-01-26 00:37:23 +01:00
|
|
|
if (hit && opt->status_only)
|
|
|
|
break;
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2010-12-15 16:02:51 +01:00
|
|
|
static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
|
2006-05-01 08:28:15 +02:00
|
|
|
struct object *obj, const char *name)
|
|
|
|
{
|
2006-07-12 05:45:31 +02:00
|
|
|
if (obj->type == OBJ_BLOB)
|
2006-08-11 09:44:42 +02:00
|
|
|
return grep_sha1(opt, obj->sha1, name, 0);
|
2006-07-12 05:45:31 +02:00
|
|
|
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
|
2006-05-01 08:28:15 +02:00
|
|
|
struct tree_desc tree;
|
|
|
|
void *data;
|
2007-03-21 18:08:25 +01:00
|
|
|
unsigned long size;
|
2010-12-17 13:44:25 +01:00
|
|
|
struct strbuf base;
|
|
|
|
int hit, len;
|
|
|
|
|
2012-02-02 09:18:41 +01:00
|
|
|
grep_read_lock();
|
2006-05-01 08:28:15 +02:00
|
|
|
data = read_object_with_reference(obj->sha1, tree_type,
|
2007-03-21 18:08:25 +01:00
|
|
|
&size, NULL);
|
2012-02-02 09:18:41 +01:00
|
|
|
grep_read_unlock();
|
2011-08-30 15:45:38 +02:00
|
|
|
|
2006-05-01 08:28:15 +02:00
|
|
|
if (!data)
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1));
|
2010-12-17 13:44:25 +01:00
|
|
|
|
|
|
|
len = name ? strlen(name) : 0;
|
|
|
|
strbuf_init(&base, PATH_MAX + len + 1);
|
|
|
|
if (len) {
|
|
|
|
strbuf_add(&base, name, len);
|
|
|
|
strbuf_addch(&base, ':');
|
|
|
|
}
|
2007-03-21 18:08:25 +01:00
|
|
|
init_tree_desc(&tree, data, size);
|
2010-12-17 13:44:25 +01:00
|
|
|
hit = grep_tree(opt, pathspec, &tree, &base, base.len);
|
|
|
|
strbuf_release(&base);
|
2006-05-01 08:28:15 +02:00
|
|
|
free(data);
|
|
|
|
return hit;
|
|
|
|
}
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("unable to grep from object of type %s"), typename(obj->type));
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
|
|
|
|
2010-12-15 16:02:51 +01:00
|
|
|
static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
|
2010-06-12 18:31:18 +02:00
|
|
|
const struct object_array *list)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int hit = 0;
|
|
|
|
const unsigned int nr = list->nr;
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
struct object *real_obj;
|
|
|
|
real_obj = deref_tag(list->objects[i].item, NULL, 0);
|
2010-12-15 16:02:51 +01:00
|
|
|
if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
|
2010-06-12 18:31:18 +02:00
|
|
|
hit = 1;
|
|
|
|
if (opt->status_only)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2011-10-05 03:40:41 +02:00
|
|
|
static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
|
|
|
|
int exc_std)
|
2010-02-06 19:40:08 +01:00
|
|
|
{
|
|
|
|
struct dir_struct dir;
|
|
|
|
int i, hit = 0;
|
|
|
|
|
|
|
|
memset(&dir, 0, sizeof(dir));
|
2011-09-27 22:43:12 +02:00
|
|
|
if (exc_std)
|
|
|
|
setup_standard_excludes(&dir);
|
2010-02-06 19:40:08 +01:00
|
|
|
|
2010-12-15 16:02:51 +01:00
|
|
|
fill_directory(&dir, pathspec->raw);
|
2010-02-06 19:40:08 +01:00
|
|
|
for (i = 0; i < dir.nr; i++) {
|
2011-02-16 23:39:00 +01:00
|
|
|
const char *name = dir.entries[i]->name;
|
|
|
|
int namelen = strlen(name);
|
|
|
|
if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
|
|
|
|
continue;
|
2010-02-06 19:40:08 +01:00
|
|
|
hit |= grep_file(opt, dir.entries[i]->name);
|
|
|
|
if (hit && opt->status_only)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int context_callback(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
int value;
|
|
|
|
const char *endp;
|
|
|
|
|
|
|
|
if (unset) {
|
|
|
|
grep_opt->pre_context = grep_opt->post_context = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
value = strtol(arg, (char **)&endp, 10);
|
|
|
|
if (*endp) {
|
2011-02-23 00:41:55 +01:00
|
|
|
return error(_("switch `%c' expects a numerical value"),
|
2009-05-07 21:46:48 +02:00
|
|
|
opt->short_name);
|
|
|
|
}
|
|
|
|
grep_opt->pre_context = grep_opt->post_context = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int file_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
2011-03-19 19:33:15 +01:00
|
|
|
int from_stdin = !strcmp(arg, "-");
|
2009-05-07 21:46:48 +02:00
|
|
|
FILE *patterns;
|
|
|
|
int lno = 0;
|
2009-10-16 16:13:25 +02:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2009-05-07 21:46:48 +02:00
|
|
|
|
2011-03-19 19:33:15 +01:00
|
|
|
patterns = from_stdin ? stdin : fopen(arg, "r");
|
2009-05-07 21:46:48 +02:00
|
|
|
if (!patterns)
|
2011-02-23 00:41:55 +01:00
|
|
|
die_errno(_("cannot open '%s'"), arg);
|
2009-05-07 21:46:48 +02:00
|
|
|
while (strbuf_getline(&sb, patterns, '\n') == 0) {
|
2010-05-22 23:43:43 +02:00
|
|
|
char *s;
|
|
|
|
size_t len;
|
|
|
|
|
2009-05-07 21:46:48 +02:00
|
|
|
/* ignore empty line like grep does */
|
|
|
|
if (sb.len == 0)
|
|
|
|
continue;
|
2010-05-22 23:43:43 +02:00
|
|
|
|
|
|
|
s = strbuf_detach(&sb, &len);
|
|
|
|
append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
|
2009-05-07 21:46:48 +02:00
|
|
|
}
|
2011-03-19 19:33:15 +01:00
|
|
|
if (!from_stdin)
|
|
|
|
fclose(patterns);
|
2009-05-07 21:46:48 +02:00
|
|
|
strbuf_release(&sb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int not_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int and_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int open_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int close_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int pattern_callback(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
struct grep_opt *grep_opt = opt->value;
|
|
|
|
append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-05-01 08:28:15 +02:00
|
|
|
|
2009-05-21 00:05:22 +02:00
|
|
|
static int help_callback(const struct option *opt, const char *arg, int unset)
|
2009-05-07 21:46:48 +02:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2006-07-04 11:44:48 +02:00
|
|
|
|
2006-07-29 07:44:25 +02:00
|
|
|
int cmd_grep(int argc, const char **argv, const char *prefix)
|
2006-05-01 08:28:15 +02:00
|
|
|
{
|
|
|
|
int hit = 0;
|
2011-09-27 22:43:12 +02:00
|
|
|
int cached = 0, untracked = 0, opt_exclude = -1;
|
2006-05-09 08:55:47 +02:00
|
|
|
int seen_dashdash = 0;
|
2010-01-13 04:06:41 +01:00
|
|
|
int external_grep_allowed__ignored;
|
2010-06-12 18:39:46 +02:00
|
|
|
const char *show_in_pager = NULL, *default_pager = "dummy";
|
2006-05-01 08:28:15 +02:00
|
|
|
struct grep_opt opt;
|
2010-08-29 04:04:17 +02:00
|
|
|
struct object_array list = OBJECT_ARRAY_INIT;
|
2006-05-02 00:58:29 +02:00
|
|
|
const char **paths = NULL;
|
2010-12-15 16:02:51 +01:00
|
|
|
struct pathspec pathspec;
|
2010-07-04 21:46:19 +02:00
|
|
|
struct string_list path_list = STRING_LIST_INIT_NODUP;
|
2006-05-09 08:55:47 +02:00
|
|
|
int i;
|
2009-05-07 21:46:48 +02:00
|
|
|
int dummy;
|
2010-08-06 05:06:39 +02:00
|
|
|
int use_index = 1;
|
2011-05-10 03:48:36 +02:00
|
|
|
enum {
|
|
|
|
pattern_type_unspecified = 0,
|
|
|
|
pattern_type_bre,
|
|
|
|
pattern_type_ere,
|
|
|
|
pattern_type_fixed,
|
|
|
|
pattern_type_pcre,
|
|
|
|
};
|
|
|
|
int pattern_type = pattern_type_unspecified;
|
|
|
|
|
2009-05-07 21:46:48 +02:00
|
|
|
struct option options[] = {
|
|
|
|
OPT_BOOLEAN(0, "cached", &cached,
|
|
|
|
"search in index instead of in the work tree"),
|
2011-09-15 20:26:02 +02:00
|
|
|
{ OPTION_BOOLEAN, 0, "index", &use_index, NULL,
|
|
|
|
"finds in contents not managed by git",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP },
|
2011-09-27 22:43:12 +02:00
|
|
|
OPT_BOOLEAN(0, "untracked", &untracked,
|
|
|
|
"search in both tracked and untracked files"),
|
|
|
|
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
|
|
|
|
"search also in ignored files", 1),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_GROUP(""),
|
|
|
|
OPT_BOOLEAN('v', "invert-match", &opt.invert,
|
|
|
|
"show non-matching lines"),
|
2009-11-06 10:22:35 +01:00
|
|
|
OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
|
|
|
|
"case insensitive matching"),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
|
|
|
|
"match patterns only at word boundaries"),
|
|
|
|
OPT_SET_INT('a', "text", &opt.binary,
|
|
|
|
"process binary files as text", GREP_BINARY_TEXT),
|
|
|
|
OPT_SET_INT('I', NULL, &opt.binary,
|
|
|
|
"don't match patterns in binary files",
|
|
|
|
GREP_BINARY_NOMATCH),
|
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-22 19:52:15 +02:00
|
|
|
{ OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth",
|
|
|
|
"descend at most <depth> levels", PARSE_OPT_NONEG,
|
|
|
|
NULL, 1 },
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_GROUP(""),
|
2011-05-10 03:48:36 +02:00
|
|
|
OPT_SET_INT('E', "extended-regexp", &pattern_type,
|
|
|
|
"use extended POSIX regular expressions",
|
|
|
|
pattern_type_ere),
|
|
|
|
OPT_SET_INT('G', "basic-regexp", &pattern_type,
|
|
|
|
"use basic POSIX regular expressions (default)",
|
|
|
|
pattern_type_bre),
|
|
|
|
OPT_SET_INT('F', "fixed-strings", &pattern_type,
|
|
|
|
"interpret patterns as fixed strings",
|
|
|
|
pattern_type_fixed),
|
|
|
|
OPT_SET_INT('P', "perl-regexp", &pattern_type,
|
|
|
|
"use Perl-compatible regular expressions",
|
|
|
|
pattern_type_pcre),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_GROUP(""),
|
2011-03-28 20:11:55 +02:00
|
|
|
OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
|
|
|
|
OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
|
|
|
|
OPT_NEGBIT(0, "full-name", &opt.relative,
|
|
|
|
"show filenames relative to top directory", 1),
|
|
|
|
OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
|
|
|
|
"show only filenames instead of matching lines"),
|
|
|
|
OPT_BOOLEAN(0, "name-only", &opt.name_only,
|
|
|
|
"synonym for --files-with-matches"),
|
|
|
|
OPT_BOOLEAN('L', "files-without-match",
|
|
|
|
&opt.unmatch_name_only,
|
|
|
|
"show only the names of files without match"),
|
|
|
|
OPT_BOOLEAN('z', "null", &opt.null_following_name,
|
|
|
|
"print NUL after filenames"),
|
|
|
|
OPT_BOOLEAN('c', "count", &opt.count,
|
|
|
|
"show the number of matches instead of matching lines"),
|
Add an optional argument for --color options
Make git-branch, git-show-branch, git-grep, and all the diff-based
programs accept an optional argument <when> for --color. The argument
is a colorbool: "always", "never", or "auto". If no argument is given,
"always" is used; --no-color is an alias for --color=never. This makes
the command-line interface consistent with other GNU tools, such as `ls'
and `grep', and with the git-config color options. Note that, without
an argument, --color and --no-color work exactly as before.
To implement this, two internal changes were made:
1. Allow the first argument of git_config_colorbool() to be NULL,
in which case it returns -1 if the argument isn't "always", "never",
or "auto".
2. Add OPT_COLOR_FLAG(), OPT__COLOR(), and parse_opt_color_flag_cb()
to the option parsing library. The callback uses
git_config_colorbool(), so color.h is now a dependency
of parse-options.c.
Signed-off-by: Mark Lodato <lodatom@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-17 05:55:58 +01:00
|
|
|
OPT__COLOR(&opt.color, "highlight matches"),
|
2011-06-05 17:24:25 +02:00
|
|
|
OPT_BOOLEAN(0, "break", &opt.file_break,
|
|
|
|
"print empty line between matches from different files"),
|
2011-06-05 17:24:36 +02:00
|
|
|
OPT_BOOLEAN(0, "heading", &opt.heading,
|
|
|
|
"show filename only once above matches from same file"),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_GROUP(""),
|
2011-08-01 19:22:52 +02:00
|
|
|
OPT_CALLBACK('C', "context", &opt, "n",
|
2009-05-07 21:46:48 +02:00
|
|
|
"show <n> context lines before and after matches",
|
|
|
|
context_callback),
|
2011-08-01 19:22:52 +02:00
|
|
|
OPT_INTEGER('B', "before-context", &opt.pre_context,
|
2009-05-07 21:46:48 +02:00
|
|
|
"show <n> context lines before matches"),
|
2011-08-01 19:22:52 +02:00
|
|
|
OPT_INTEGER('A', "after-context", &opt.post_context,
|
2009-05-07 21:46:48 +02:00
|
|
|
"show <n> context lines after matches"),
|
|
|
|
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
|
|
|
|
context_callback),
|
2009-07-02 00:06:34 +02:00
|
|
|
OPT_BOOLEAN('p', "show-function", &opt.funcname,
|
|
|
|
"show a line with the function name before matches"),
|
2011-08-01 19:22:52 +02:00
|
|
|
OPT_BOOLEAN('W', "function-context", &opt.funcbody,
|
2011-08-01 19:20:53 +02:00
|
|
|
"show the surrounding function"),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_GROUP(""),
|
|
|
|
OPT_CALLBACK('f', NULL, &opt, "file",
|
|
|
|
"read patterns from file", file_callback),
|
|
|
|
{ OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
|
|
|
|
"match <pattern>", PARSE_OPT_NONEG, pattern_callback },
|
|
|
|
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
|
|
|
|
"combine patterns specified with -e",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
|
|
|
|
OPT_BOOLEAN(0, "or", &dummy, ""),
|
|
|
|
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
|
|
|
|
{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
|
|
|
|
open_callback },
|
|
|
|
{ OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
|
|
|
|
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
|
|
|
|
close_callback },
|
2010-11-08 19:06:54 +01:00
|
|
|
OPT__QUIET(&opt.status_only,
|
|
|
|
"indicate hit with exit status without output"),
|
2009-05-07 21:46:48 +02:00
|
|
|
OPT_BOOLEAN(0, "all-match", &opt.all_match,
|
|
|
|
"show only matches from files that match all patterns"),
|
|
|
|
OPT_GROUP(""),
|
2010-06-12 18:39:46 +02:00
|
|
|
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
|
|
|
|
"pager", "show matching files in the pager",
|
|
|
|
PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
|
2010-01-13 04:06:41 +01:00
|
|
|
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored,
|
|
|
|
"allow calling of grep(1) (ignored by this build)"),
|
2009-05-07 21:46:48 +02:00
|
|
|
{ OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
|
|
|
|
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
|
|
|
|
OPT_END()
|
|
|
|
};
|
2006-05-01 08:28:15 +02:00
|
|
|
|
2009-11-09 16:04:42 +01:00
|
|
|
/*
|
|
|
|
* 'git grep -h', unlike 'git grep -h <pattern>', is a request
|
|
|
|
* to show usage information and exit.
|
|
|
|
*/
|
|
|
|
if (argc == 2 && !strcmp(argv[1], "-h"))
|
|
|
|
usage_with_options(grep_usage, options);
|
|
|
|
|
2006-05-01 08:28:15 +02:00
|
|
|
memset(&opt, 0, sizeof(opt));
|
2009-09-05 14:31:17 +02:00
|
|
|
opt.prefix = prefix;
|
2006-08-11 09:44:42 +02:00
|
|
|
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
|
|
|
|
opt.relative = 1;
|
2006-09-14 19:45:12 +02:00
|
|
|
opt.pathname = 1;
|
2006-05-03 00:40:49 +02:00
|
|
|
opt.pattern_tail = &opt.pattern_list;
|
"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 05:09:06 +01:00
|
|
|
opt.header_tail = &opt.header_list;
|
2006-05-01 08:28:15 +02:00
|
|
|
opt.regflags = REG_NEWLINE;
|
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-22 19:52:15 +02:00
|
|
|
opt.max_depth = -1;
|
2006-05-01 08:28:15 +02:00
|
|
|
|
2010-03-07 17:52:47 +01:00
|
|
|
strcpy(opt.color_context, "");
|
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-07 17:52:46 +01:00
|
|
|
strcpy(opt.color_filename, "");
|
2010-03-07 17:52:47 +01:00
|
|
|
strcpy(opt.color_function, "");
|
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-07 17:52:46 +01:00
|
|
|
strcpy(opt.color_lineno, "");
|
2010-03-07 17:52:45 +01:00
|
|
|
strcpy(opt.color_match, GIT_COLOR_BOLD_RED);
|
2010-03-07 17:52:47 +01:00
|
|
|
strcpy(opt.color_selected, "");
|
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-07 17:52:46 +01:00
|
|
|
strcpy(opt.color_sep, GIT_COLOR_CYAN);
|
2009-03-07 13:32:32 +01:00
|
|
|
opt.color = -1;
|
|
|
|
git_config(grep_config, &opt);
|
|
|
|
|
2006-05-01 08:28:15 +02:00
|
|
|
/*
|
2006-05-09 08:55:47 +02:00
|
|
|
* If there is no -- then the paths must exist in the working
|
|
|
|
* tree. If there is no explicit pattern specified with -e or
|
|
|
|
* -f, we take the first unrecognized non option to be the
|
|
|
|
* pattern, but then what follows it must be zero or more
|
|
|
|
* valid refs up to the -- (if exists), and then existing
|
|
|
|
* paths. If there is an explicit pattern, then the first
|
2006-07-10 07:50:18 +02:00
|
|
|
* unrecognized non option is the beginning of the refs list
|
2006-05-09 08:55:47 +02:00
|
|
|
* that continues up to the -- (if exists), and then paths.
|
2006-05-01 08:28:15 +02:00
|
|
|
*/
|
2009-05-23 20:53:12 +02:00
|
|
|
argc = parse_options(argc, argv, prefix, options, grep_usage,
|
2009-05-07 21:46:48 +02:00
|
|
|
PARSE_OPT_KEEP_DASHDASH |
|
|
|
|
PARSE_OPT_STOP_AT_NON_OPTION |
|
|
|
|
PARSE_OPT_NO_INTERNAL_HELP);
|
2011-05-10 03:48:36 +02:00
|
|
|
switch (pattern_type) {
|
|
|
|
case pattern_type_fixed:
|
|
|
|
opt.fixed = 1;
|
|
|
|
opt.pcre = 0;
|
|
|
|
break;
|
|
|
|
case pattern_type_bre:
|
|
|
|
opt.fixed = 0;
|
|
|
|
opt.pcre = 0;
|
|
|
|
opt.regflags &= ~REG_EXTENDED;
|
|
|
|
break;
|
|
|
|
case pattern_type_ere:
|
|
|
|
opt.fixed = 0;
|
|
|
|
opt.pcre = 0;
|
|
|
|
opt.regflags |= REG_EXTENDED;
|
|
|
|
break;
|
|
|
|
case pattern_type_pcre:
|
|
|
|
opt.fixed = 0;
|
|
|
|
opt.pcre = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break; /* nothing */
|
|
|
|
}
|
2009-05-07 21:46:48 +02:00
|
|
|
|
2010-08-06 05:06:39 +02:00
|
|
|
if (use_index && !startup_info->have_repository)
|
2010-02-06 19:40:08 +01:00
|
|
|
/* die the same way as if we did it at the beginning */
|
|
|
|
setup_git_directory();
|
|
|
|
|
2010-02-07 05:44:15 +01:00
|
|
|
/*
|
|
|
|
* skip a -- separator; we know it cannot be
|
|
|
|
* separating revisions from pathnames if
|
|
|
|
* we haven't even had any patterns yet
|
|
|
|
*/
|
|
|
|
if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) {
|
|
|
|
argv++;
|
|
|
|
argc--;
|
|
|
|
}
|
|
|
|
|
2009-05-07 21:46:48 +02:00
|
|
|
/* First unrecognized non-option token */
|
|
|
|
if (argc > 0 && !opt.pattern_list) {
|
|
|
|
append_grep_pattern(&opt, argv[0], "command line", 0,
|
|
|
|
GREP_PATTERN);
|
|
|
|
argv++;
|
|
|
|
argc--;
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
2006-05-09 08:55:47 +02:00
|
|
|
|
2010-06-12 18:39:46 +02:00
|
|
|
if (show_in_pager == default_pager)
|
|
|
|
show_in_pager = git_pager(1);
|
2010-06-12 18:36:51 +02:00
|
|
|
if (show_in_pager) {
|
2010-07-03 04:55:06 +02:00
|
|
|
opt.color = 0;
|
2010-06-12 18:39:46 +02:00
|
|
|
opt.name_only = 1;
|
|
|
|
opt.null_following_name = 1;
|
|
|
|
opt.output_priv = &path_list;
|
|
|
|
opt.output = append_path;
|
2010-06-26 01:41:39 +02:00
|
|
|
string_list_append(&path_list, show_in_pager);
|
2010-06-12 18:39:46 +02:00
|
|
|
use_threads = 0;
|
2010-06-12 18:36:51 +02:00
|
|
|
}
|
|
|
|
|
2006-05-03 00:40:49 +02:00
|
|
|
if (!opt.pattern_list)
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("no pattern given."));
|
2009-11-06 10:22:35 +01:00
|
|
|
if (!opt.fixed && opt.ignore_case)
|
|
|
|
opt.regflags |= REG_ICASE;
|
2010-01-25 23:51:39 +01:00
|
|
|
|
2006-09-18 01:02:52 +02:00
|
|
|
compile_grep_patterns(&opt);
|
2006-05-09 08:55:47 +02:00
|
|
|
|
|
|
|
/* Check revs and then paths */
|
2009-05-07 21:46:48 +02:00
|
|
|
for (i = 0; i < argc; i++) {
|
2006-05-09 08:55:47 +02:00
|
|
|
const char *arg = argv[i];
|
2006-05-02 00:58:29 +02:00
|
|
|
unsigned char sha1[20];
|
2006-05-09 08:55:47 +02:00
|
|
|
/* Is it a rev? */
|
|
|
|
if (!get_sha1(arg, sha1)) {
|
|
|
|
struct object *object = parse_object(sha1);
|
|
|
|
if (!object)
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("bad object %s"), arg);
|
Add "named object array" concept
We've had this notion of a "object_list" for a long time, which eventually
grew a "name" member because some users (notably git-rev-list) wanted to
name each object as it is generated.
That object_list is great for some things, but it isn't all that wonderful
for others, and the "name" member is generally not used by everybody.
This patch splits the users of the object_list array up into two: the
traditional list users, who want the list-like format, and who don't
actually use or want the name. And another class of users that really used
the list as an extensible array, and generally wanted to name the objects.
The patch is fairly straightforward, but it's also biggish. Most of it
really just cleans things up: switching the revision parsing and listing
over to the array makes things like the builtin-diff usage much simpler
(we now see exactly how many members the array has, and we don't get the
objects reversed from the order they were on the command line).
One of the main reasons for doing this at all is that the malloc overhead
of the simple object list was actually pretty high, and the array is just
a lot denser. So this patch brings down memory usage by git-rev-list by
just under 3% (on top of all the other memory use optimizations) on the
mozilla archive.
It does add more lines than it removes, and more importantly, it adds a
whole new infrastructure for maintaining lists of objects, but on the
other hand, the new dynamic array code is pretty obvious. The change to
builtin-diff-tree.c shows a fairly good example of why an array interface
is sometimes more natural, and just much simpler for everybody.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-20 02:42:35 +02:00
|
|
|
add_object_array(object, arg, &list);
|
2006-05-09 08:55:47 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--")) {
|
|
|
|
i++;
|
|
|
|
seen_dashdash = 1;
|
|
|
|
}
|
|
|
|
break;
|
2006-05-02 00:58:29 +02:00
|
|
|
}
|
2006-05-09 08:55:47 +02:00
|
|
|
|
2011-12-12 22:16:08 +01:00
|
|
|
#ifndef NO_PTHREADS
|
|
|
|
if (list.nr || cached || online_cpus() == 1)
|
|
|
|
use_threads = 0;
|
|
|
|
#else
|
|
|
|
use_threads = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef NO_PTHREADS
|
|
|
|
if (use_threads) {
|
2012-01-23 18:52:44 +01:00
|
|
|
if (!(opt.name_only || opt.unmatch_name_only || opt.count)
|
|
|
|
&& (opt.pre_context || opt.post_context ||
|
|
|
|
opt.file_break || opt.funcbody))
|
2011-12-12 22:16:08 +01:00
|
|
|
skip_first_line = 1;
|
|
|
|
start_threads(&opt);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-05-09 08:55:47 +02:00
|
|
|
/* The rest are paths */
|
|
|
|
if (!seen_dashdash) {
|
|
|
|
int j;
|
2006-05-10 03:15:21 +02:00
|
|
|
for (j = i; j < argc; j++)
|
2006-05-09 08:55:47 +02:00
|
|
|
verify_filename(prefix, argv[j]);
|
|
|
|
}
|
|
|
|
|
2011-05-10 06:34:04 +02:00
|
|
|
paths = get_pathspec(prefix, argv + i);
|
2010-12-15 16:02:51 +01:00
|
|
|
init_pathspec(&pathspec, paths);
|
2010-12-17 13:45:33 +01:00
|
|
|
pathspec.max_depth = opt.max_depth;
|
|
|
|
pathspec.recursive = 1;
|
2006-05-01 08:28:15 +02:00
|
|
|
|
2010-06-12 18:36:51 +02:00
|
|
|
if (show_in_pager && (cached || list.nr))
|
2011-02-23 00:41:56 +01:00
|
|
|
die(_("--open-files-in-pager only works on the worktree"));
|
2010-06-12 18:36:51 +02:00
|
|
|
|
|
|
|
if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) {
|
|
|
|
const char *pager = path_list.items[0].string;
|
|
|
|
int len = strlen(pager);
|
|
|
|
|
|
|
|
if (len > 4 && is_dir_sep(pager[len - 5]))
|
|
|
|
pager += len - 4;
|
|
|
|
|
|
|
|
if (!strcmp("less", pager) || !strcmp("vi", pager)) {
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
strbuf_addf(&buf, "+/%s%s",
|
|
|
|
strcmp("less", pager) ? "" : "*",
|
|
|
|
opt.pattern_list->pattern);
|
2010-06-26 01:41:39 +02:00
|
|
|
string_list_append(&path_list, buf.buf);
|
2010-06-12 18:36:51 +02:00
|
|
|
strbuf_detach(&buf, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!show_in_pager)
|
|
|
|
setup_pager();
|
|
|
|
|
2011-09-27 22:43:12 +02:00
|
|
|
if (!use_index && (untracked || cached))
|
2011-10-05 03:40:41 +02:00
|
|
|
die(_("--cached or --untracked cannot be used with --no-index."));
|
2010-06-12 18:36:51 +02:00
|
|
|
|
2011-09-27 22:43:12 +02:00
|
|
|
if (!use_index || untracked) {
|
|
|
|
int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
|
2010-02-06 19:40:08 +01:00
|
|
|
if (list.nr)
|
2011-10-05 03:40:41 +02:00
|
|
|
die(_("--no-index or --untracked cannot be used with revs."));
|
|
|
|
hit = grep_directory(&opt, &pathspec, use_exclude);
|
|
|
|
} else if (0 <= opt_exclude) {
|
2011-10-16 05:26:52 +02:00
|
|
|
die(_("--[no-]exclude-standard cannot be used for tracked contents."));
|
2010-06-12 18:32:11 +02:00
|
|
|
} else if (!list.nr) {
|
2008-08-28 15:04:30 +02:00
|
|
|
if (!cached)
|
|
|
|
setup_work_tree();
|
2010-01-25 23:51:39 +01:00
|
|
|
|
2010-12-15 16:02:51 +01:00
|
|
|
hit = grep_cache(&opt, &pathspec, cached);
|
2010-06-12 18:32:11 +02:00
|
|
|
} else {
|
|
|
|
if (cached)
|
2011-02-23 00:41:55 +01:00
|
|
|
die(_("both --cached and trees are given."));
|
2010-12-15 16:02:51 +01:00
|
|
|
hit = grep_objects(&opt, &pathspec, &list);
|
2006-05-01 08:28:15 +02:00
|
|
|
}
|
2010-01-25 23:51:39 +01:00
|
|
|
|
|
|
|
if (use_threads)
|
|
|
|
hit |= wait_all();
|
2010-06-12 18:36:51 +02:00
|
|
|
if (hit && show_in_pager)
|
|
|
|
run_pager(&opt, prefix);
|
2006-09-28 01:27:10 +02:00
|
|
|
free_grep_patterns(&opt);
|
2006-05-01 08:28:15 +02:00
|
|
|
return !hit;
|
|
|
|
}
|