Code

svn: properly escape arguments for authors-prog
[git.git] / builtin-grep.c
index 48998af9115379f97403e0aeb63ac46f041906eb..fd450bc16e56a634b14cfa33f77e5192412643d8 100644 (file)
@@ -11,7 +11,9 @@
 #include "tree-walk.h"
 #include "builtin.h"
 #include "parse-options.h"
+#include "userdiff.h"
 #include "grep.h"
+#include "quote.h"
 
 #ifndef NO_EXTERNAL_GREP
 #ifdef __unix__
@@ -30,6 +32,12 @@ static int grep_config(const char *var, const char *value, void *cb)
 {
        struct grep_opt *opt = cb;
 
+       switch (userdiff_config(var, value)) {
+       case 0: break;
+       case -1: return -1;
+       default: return 0;
+       }
+
        if (!strcmp(var, "color.grep")) {
                opt->color = git_config_colorbool(var, value, -1);
                return 0;
@@ -118,8 +126,8 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char
        unsigned long size;
        char *data;
        enum object_type type;
-       char *to_free = NULL;
        int hit;
+       struct strbuf pathbuf = STRBUF_INIT;
 
        data = read_sha1_file(sha1, &type, &size);
        if (!data) {
@@ -127,26 +135,13 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char
                return 0;
        }
        if (opt->relative && opt->prefix_length) {
-               static char name_buf[PATH_MAX];
-               char *cp;
-               int name_len = strlen(name) - opt->prefix_length + 1;
-
-               if (!tree_name_len)
-                       name += opt->prefix_length;
-               else {
-                       if (ARRAY_SIZE(name_buf) <= name_len)
-                               cp = to_free = xmalloc(name_len);
-                       else
-                               cp = name_buf;
-                       memcpy(cp, name, tree_name_len);
-                       strcpy(cp + tree_name_len,
-                              name + tree_name_len + opt->prefix_length);
-                       name = cp;
-               }
+               quote_path_relative(name + tree_name_len, -1, &pathbuf, opt->prefix);
+               strbuf_insert(&pathbuf, 0, name, tree_name_len);
+               name = pathbuf.buf;
        }
        hit = grep_buffer(opt, name, data, size);
+       strbuf_release(&pathbuf);
        free(data);
-       free(to_free);
        return hit;
 }
 
@@ -156,6 +151,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
        int i;
        char *data;
        size_t sz;
+       struct strbuf buf = STRBUF_INIT;
 
        if (lstat(filename, &st) < 0) {
        err_ret:
@@ -180,8 +176,9 @@ static int grep_file(struct grep_opt *opt, const char *filename)
        }
        close(i);
        if (opt->relative && opt->prefix_length)
-               filename += opt->prefix_length;
+               filename = quote_path_relative(filename, -1, &buf, opt->prefix);
        i = grep_buffer(opt, filename, data, sz);
+       strbuf_release(&buf);
        free(data);
        return i;
 }
@@ -464,6 +461,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
                hit = external_grep(opt, paths, cached);
                if (hit >= 0)
                        return hit;
+               hit = 0;
        }
 #endif
 
@@ -605,7 +603,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
 
        patterns = fopen(arg, "r");
        if (!patterns)
-               die("'%s': %s", arg, strerror(errno));
+               die_errno("cannot open '%s'", arg);
        while (strbuf_getline(&sb, patterns, '\n') == 0) {
                /* ignore empty line like grep does */
                if (sb.len == 0)
@@ -721,6 +719,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        "show <n> context lines after matches"),
                OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
                        context_callback),
+               OPT_BOOLEAN('p', "show-function", &opt.funcname,
+                       "show a line with the function name before matches"),
                OPT_GROUP(""),
                OPT_CALLBACK('f', NULL, &opt, "file",
                        "read patterns from file", file_callback),
@@ -754,6 +754,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        };
 
        memset(&opt, 0, sizeof(opt));
+       opt.prefix = prefix;
        opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
        opt.relative = 1;
        opt.pathname = 1;
@@ -789,7 +790,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                argc--;
        }
 
-       if (opt.color && !opt.color_external)
+       if ((opt.color && !opt.color_external) || opt.funcname)
                external_grep_allowed = 0;
        if (!opt.pattern_list)
                die("no pattern given.");
@@ -823,15 +824,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        verify_filename(prefix, argv[j]);
        }
 
-       if (i < argc) {
+       if (i < argc)
                paths = get_pathspec(prefix, argv + i);
-               if (opt.prefix_length && opt.relative) {
-                       /* Make sure we do not get outside of paths */
-                       for (i = 0; paths[i]; i++)
-                               if (strncmp(prefix, paths[i], opt.prefix_length))
-                                       die("git grep: cannot generate relative filenames containing '..'");
-               }
-       }
        else if (prefix) {
                paths = xcalloc(2, sizeof(const char *));
                paths[0] = prefix;