xsize_t: check whether we lose bits
[gitweb.git] / builtin-grep.c
index ad7dc00cde4e8e08ef35b313525781c135357df3..694da5ba09d302c1e44f863070776bc3ac7f32e2 100644 (file)
 #include "tag.h"
 #include "tree-walk.h"
 #include "builtin.h"
-#include <regex.h>
 #include "grep.h"
-#include <fnmatch.h>
-#include <sys/wait.h>
 
 /*
  * git grep pathspecs are somewhat different from diff-tree pathspecs;
@@ -87,11 +84,11 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char
 {
        unsigned long size;
        char *data;
-       char type[20];
+       enum object_type type;
        char *to_free = NULL;
        int hit;
 
-       data = read_sha1_file(sha1, type, &size);
+       data = read_sha1_file(sha1, &type, &size);
        if (!data) {
                error("'%s': unable to read %s", name, sha1_to_hex(sha1));
                return 0;
@@ -125,6 +122,8 @@ static int grep_file(struct grep_opt *opt, const char *filename)
        struct stat st;
        int i;
        char *data;
+       size_t sz;
+
        if (lstat(filename, &st) < 0) {
        err_ret:
                if (errno != ENOENT)
@@ -135,11 +134,12 @@ static int grep_file(struct grep_opt *opt, const char *filename)
                return 0; /* empty file -- no grep hit */
        if (!S_ISREG(st.st_mode))
                return 0;
+       sz = xsize_t(st.st_size);
        i = open(filename, O_RDONLY);
        if (i < 0)
                goto err_ret;
-       data = xmalloc(st.st_size + 1);
-       if (st.st_size != xread(i, data, st.st_size)) {
+       data = xmalloc(sz + 1);
+       if (st.st_size != read_in_full(i, data, sz)) {
                error("'%s': short read %s", filename, strerror(errno));
                close(i);
                free(data);
@@ -148,11 +148,12 @@ static int grep_file(struct grep_opt *opt, const char *filename)
        close(i);
        if (opt->relative && opt->prefix_length)
                filename += opt->prefix_length;
-       i = grep_buffer(opt, filename, data, st.st_size);
+       i = grep_buffer(opt, filename, data, sz);
        free(data);
        return i;
 }
 
+#ifdef __unix__
 static int exec_grep(int argc, const char **argv)
 {
        pid_t pid;
@@ -268,7 +269,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = active_cache[i];
                char *name;
-               if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
+               if (!S_ISREG(ntohl(ce->ce_mode)))
                        continue;
                if (!pathspec_matches(paths, ce->name))
                        continue;
@@ -280,12 +281,19 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
                        memcpy(name + 2, ce->name, len + 1);
                }
                argv[argc++] = name;
-               if (argc < MAXARGS)
+               if (argc < MAXARGS && !ce_stage(ce))
                        continue;
                status = exec_grep(argc, argv);
                if (0 < status)
                        hit = 1;
                argc = nr;
+               if (ce_stage(ce)) {
+                       do {
+                               i++;
+                       } while (i < active_nr &&
+                                !strcmp(ce->name, active_cache[i]->name));
+                       i--; /* compensate for loop control */
+               }
        }
        if (argc > nr) {
                status = exec_grep(argc, argv);
@@ -294,6 +302,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
        }
        return hit;
 }
+#endif
 
 static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 {
@@ -316,14 +325,24 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 
        for (nr = 0; nr < active_nr; nr++) {
                struct cache_entry *ce = active_cache[nr];
-               if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
+               if (!S_ISREG(ntohl(ce->ce_mode)))
                        continue;
                if (!pathspec_matches(paths, ce->name))
                        continue;
-               if (cached)
+               if (cached) {
+                       if (ce_stage(ce))
+                               continue;
                        hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
+               }
                else
                        hit |= grep_file(opt, ce->name);
+               if (ce_stage(ce)) {
+                       do {
+                               nr++;
+                       } while (nr < active_nr &&
+                                !strcmp(ce->name, active_cache[nr]->name));
+                       nr--; /* compensate for loop control */
+               }
        }
        free_grep_patterns(opt);
        return hit;
@@ -366,10 +385,10 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
                else if (S_ISREG(entry.mode))
                        hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len);
                else if (S_ISDIR(entry.mode)) {
-                       char type[20];
+                       enum object_type type;
                        struct tree_desc sub;
                        void *data;
-                       data = read_sha1_file(entry.sha1, type, &sub.size);
+                       data = read_sha1_file(entry.sha1, &type, &sub.size);
                        if (!data)
                                die("unable to read tree (%s)",
                                    sha1_to_hex(entry.sha1));
@@ -513,9 +532,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        opt.word_regexp = 1;
                        continue;
                }
-               if (!strncmp("-A", arg, 2) ||
-                   !strncmp("-B", arg, 2) ||
-                   !strncmp("-C", arg, 2) ||
+               if (!prefixcmp(arg, "-A") ||
+                   !prefixcmp(arg, "-B") ||
+                   !prefixcmp(arg, "-C") ||
                    (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
                        unsigned num;
                        const char *scan;