Work around sed and make interactions on the backslash at the end of line.
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index e73c0c3008407f24c8b150cb62f97bd37db6502f..5a71489a471568fb3aa51af5d74fa269ec4fadf1 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -743,7 +743,7 @@ static void builtin_diff(const char *name_a,
                memset(&ecbdata, 0, sizeof(ecbdata));
                ecbdata.label_path = lbl;
                ecbdata.color_diff = o->color_diff;
-               xpp.flags = XDF_NEED_MINIMAL;
+               xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
                if (!diffopts)
@@ -768,6 +768,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                             struct diff_filespec *one,
                             struct diff_filespec *two,
                             struct diffstat_t *diffstat,
+                            struct diff_options *o,
                             int complete_rewrite)
 {
        mmfile_t mf1, mf2;
@@ -797,7 +798,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                xdemitconf_t xecfg;
                xdemitcb_t ecb;
 
-               xpp.flags = XDF_NEED_MINIMAL;
+               xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = 0;
                xecfg.flags = 0;
                ecb.outf = xdiff_outf;
@@ -1382,7 +1383,7 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
 
        if (DIFF_PAIR_UNMERGED(p)) {
                /* unmerged */
-               builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, 0);
+               builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0);
                return;
        }
 
@@ -1394,7 +1395,7 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
 
        if (p->status == DIFF_STATUS_MODIFIED && p->score)
                complete_rewrite = 1;
-       builtin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite);
+       builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite);
 }
 
 static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
@@ -1600,6 +1601,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if (!strcmp(arg, "--color"))
                options->color_diff = 1;
+       else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
+               options->xdl_opts |= XDF_IGNORE_WHITESPACE;
+       else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
+               options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else
                return 0;
        return 1;
@@ -2099,6 +2104,145 @@ static void diff_summary(struct diff_filepair *p)
        }
 }
 
+struct patch_id_t {
+       struct xdiff_emit_state xm;
+       SHA_CTX *ctx;
+       int patchlen;
+};
+
+static int remove_space(char *line, int len)
+{
+       int i;
+        char *dst = line;
+        unsigned char c;
+
+        for (i = 0; i < len; i++)
+                if (!isspace((c = line[i])))
+                        *dst++ = c;
+
+        return dst - line;
+}
+
+static void patch_id_consume(void *priv, char *line, unsigned long len)
+{
+       struct patch_id_t *data = priv;
+       int new_len;
+
+       /* Ignore line numbers when computing the SHA1 of the patch */
+       if (!strncmp(line, "@@ -", 4))
+               return;
+
+       new_len = remove_space(line, len);
+
+       SHA1_Update(data->ctx, line, new_len);
+       data->patchlen += new_len;
+}
+
+/* returns 0 upon success, and writes result into sha1 */
+static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
+{
+       struct diff_queue_struct *q = &diff_queued_diff;
+       int i;
+       SHA_CTX ctx;
+       struct patch_id_t data;
+       char buffer[PATH_MAX * 4 + 20];
+
+       SHA1_Init(&ctx);
+       memset(&data, 0, sizeof(struct patch_id_t));
+       data.ctx = &ctx;
+       data.xm.consume = patch_id_consume;
+
+       for (i = 0; i < q->nr; i++) {
+               xpparam_t xpp;
+               xdemitconf_t xecfg;
+               xdemitcb_t ecb;
+               mmfile_t mf1, mf2;
+               struct diff_filepair *p = q->queue[i];
+               int len1, len2;
+
+               if (p->status == 0)
+                       return error("internal diff status error");
+               if (p->status == DIFF_STATUS_UNKNOWN)
+                       continue;
+               if (diff_unmodified_pair(p))
+                       continue;
+               if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
+                   (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
+                       continue;
+               if (DIFF_PAIR_UNMERGED(p))
+                       continue;
+
+               diff_fill_sha1_info(p->one);
+               diff_fill_sha1_info(p->two);
+               if (fill_mmfile(&mf1, p->one) < 0 ||
+                               fill_mmfile(&mf2, p->two) < 0)
+                       return error("unable to read files to diff");
+
+               /* Maybe hash p->two? into the patch id? */
+               if (mmfile_is_binary(&mf2))
+                       continue;
+
+               len1 = remove_space(p->one->path, strlen(p->one->path));
+               len2 = remove_space(p->two->path, strlen(p->two->path));
+               if (p->one->mode == 0)
+                       len1 = snprintf(buffer, sizeof(buffer),
+                                       "diff--gita/%.*sb/%.*s"
+                                       "newfilemode%06o"
+                                       "---/dev/null"
+                                       "+++b/%.*s",
+                                       len1, p->one->path,
+                                       len2, p->two->path,
+                                       p->two->mode,
+                                       len2, p->two->path);
+               else if (p->two->mode == 0)
+                       len1 = snprintf(buffer, sizeof(buffer),
+                                       "diff--gita/%.*sb/%.*s"
+                                       "deletedfilemode%06o"
+                                       "---a/%.*s"
+                                       "+++/dev/null",
+                                       len1, p->one->path,
+                                       len2, p->two->path,
+                                       p->one->mode,
+                                       len1, p->one->path);
+               else
+                       len1 = snprintf(buffer, sizeof(buffer),
+                                       "diff--gita/%.*sb/%.*s"
+                                       "---a/%.*s"
+                                       "+++b/%.*s",
+                                       len1, p->one->path,
+                                       len2, p->two->path,
+                                       len1, p->one->path,
+                                       len2, p->two->path);
+               SHA1_Update(&ctx, buffer, len1);
+
+               xpp.flags = XDF_NEED_MINIMAL;
+               xecfg.ctxlen = 3;
+               xecfg.flags = XDL_EMIT_FUNCNAMES;
+               ecb.outf = xdiff_outf;
+               ecb.priv = &data;
+               xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+       }
+
+       SHA1_Final(sha1, &ctx);
+       return 0;
+}
+
+int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
+{
+       struct diff_queue_struct *q = &diff_queued_diff;
+       int i;
+       int result = diff_get_patch_id(options, sha1);
+
+       for (i = 0; i < q->nr; i++)
+               diff_free_filepair(q->queue[i]);
+
+       free(q->queue);
+       q->queue = NULL;
+       q->nr = q->alloc = 0;
+
+       return result;
+}
+
 void diff_flush(struct diff_options *options)
 {
        struct diff_queue_struct *q = &diff_queued_diff;