ls-tree: major rewrite to do pathspec
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index ec94a96a5d02fe4204cc69f03de2966264378f75..2e0797bf3ee651a644be50aee10ee125fe96368f 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -13,6 +13,18 @@ static const char *diff_opts = "-pu";
 
 static int use_size_cache;
 
+int diff_rename_limit_default = -1;
+
+int git_diff_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "diff.renamelimit")) {
+               diff_rename_limit_default = git_config_int(var, value);
+               return 0;
+       }
+
+       return git_default_config(var, value);
+}
+
 static char *quote_one(const char *str)
 {
        int needlen;
@@ -648,7 +660,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
                memset(one->sha1, 0, 20);
 }
 
-static void run_diff(struct diff_filepair *p)
+static void run_diff(struct diff_filepair *p, struct diff_options *o)
 {
        const char *pgm = external_diff();
        char msg[PATH_MAX*2+300], *xfrm_msg;
@@ -711,11 +723,11 @@ static void run_diff(struct diff_filepair *p)
 
        if (memcmp(one->sha1, two->sha1, 20)) {
                char one_sha1[41];
+               const char *index_fmt = o->full_index ? "index %s..%s" : "index %.7s..%.7s";
                memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
 
                len += snprintf(msg + len, sizeof(msg) - len,
-                               "index %.7s..%.7s", one_sha1,
-                               sha1_to_hex(two->sha1));
+                               index_fmt, one_sha1, sha1_to_hex(two->sha1));
                if (one->mode == two->mode)
                        len += snprintf(msg + len, sizeof(msg) - len,
                                        " %06o", one->mode);
@@ -761,9 +773,12 @@ void diff_setup(struct diff_options *options)
 
 int diff_setup_done(struct diff_options *options)
 {
-       if ((options->find_copies_harder || 0 <= options->rename_limit) &&
-           options->detect_rename != DIFF_DETECT_COPY)
+       if ((options->find_copies_harder &&
+            options->detect_rename != DIFF_DETECT_COPY) ||
+           (0 <= options->rename_limit && !options->detect_rename))
                return -1;
+       if (options->detect_rename && options->rename_limit < 0)
+               options->rename_limit = diff_rename_limit_default;
        if (options->setup & DIFF_SETUP_USE_CACHE) {
                if (!active_cache)
                        /* read-cache does not die even when it fails
@@ -789,6 +804,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->line_termination = 0;
        else if (!strncmp(arg, "-l", 2))
                options->rename_limit = strtoul(arg+2, NULL, 10);
+       else if (!strcmp(arg, "--full-index"))
+               options->full_index = 1;
        else if (!strcmp(arg, "--name-only"))
                options->output_format = DIFF_FORMAT_NAME;
        else if (!strcmp(arg, "--name-status"))
@@ -831,16 +848,29 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 
 static int parse_num(const char **cp_p)
 {
-       int num, scale, ch, cnt;
+       unsigned long num, scale;
+       int ch, dot;
        const char *cp = *cp_p;
 
-       cnt = num = 0;
+       num = 0;
        scale = 1;
-       while ('0' <= (ch = *cp) && ch <= '9') {
-               if (cnt++ < 5) {
-                       /* We simply ignore more than 5 digits precision. */
-                       scale *= 10;
-                       num = num * 10 + ch - '0';
+       dot = 0;
+       for(;;) {
+               ch = *cp;
+               if ( !dot && ch == '.' ) {
+                       scale = 1;
+                       dot = 1;
+               } else if ( ch == '%' ) {
+                       scale = dot ? scale*100 : 100;
+                       cp++;   /* % is always at the end */
+                       break;
+               } else if ( ch >= '0' && ch <= '9' ) {
+                       if ( scale < 100000 ) {
+                               scale *= 10;
+                               num = (num*10) + (ch-'0');
+                       }
+               } else {
+                       break;
                }
                cp++;
        }
@@ -849,7 +879,7 @@ static int parse_num(const char **cp_p)
        /* user says num divided by scale and we say internally that
         * is MAX_SCORE * num / scale.
         */
-       return (MAX_SCORE * num / scale);
+       return (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);
 }
 
 int diff_scoreopt_parse(const char *opt)
@@ -1017,7 +1047,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
        return 0;
 }
 
-static void diff_flush_patch(struct diff_filepair *p)
+static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
 {
        if (diff_unmodified_pair(p))
                return;
@@ -1026,7 +1056,7 @@ static void diff_flush_patch(struct diff_filepair *p)
            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
                return; /* no tree diffs in patch format */ 
 
-       run_diff(p);
+       run_diff(p, o);
 }
 
 int diff_queue_is_empty(void)
@@ -1158,7 +1188,7 @@ void diff_flush(struct diff_options *options)
                        die("internal error in diff-resolve-rename-copy");
                switch (diff_output_format) {
                case DIFF_FORMAT_PATCH:
-                       diff_flush_patch(p);
+                       diff_flush_patch(p, options);
                        break;
                case DIFF_FORMAT_RAW:
                case DIFF_FORMAT_NAME_STATUS: