]> git.ipfire.org Git - thirdparty/git.git/blobdiff - diff.c
War on whitespace: first, a bit of retreat.
[thirdparty/git.git] / diff.c
diff --git a/diff.c b/diff.c
index 6648e015213913e693b4450230a5a0896a21f7a0..211235376de2166593945a646dcfa97405dc74d0 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -9,6 +9,7 @@
 #include "xdiff-interface.h"
 #include "color.h"
 #include "attr.h"
+#include "run-command.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -507,7 +508,8 @@ static void emit_line_with_ws(int nparents,
        for (i = col0; i < len; i++) {
                if (line[i] == '\t') {
                        last_tab_in_indent = i;
-                       if (0 <= last_space_in_indent)
+                       if ((whitespace_rule & WS_SPACE_BEFORE_TAB) &&
+                           0 <= last_space_in_indent)
                                need_highlight_leading_space = 1;
                }
                else if (line[i] == ' ')
@@ -539,10 +541,12 @@ static void emit_line_with_ws(int nparents,
        tail = len - 1;
        if (line[tail] == '\n' && i < tail)
                tail--;
-       while (i < tail) {
-               if (!isspace(line[tail]))
-                       break;
-               tail--;
+       if (whitespace_rule & WS_TRAILING_SPACE) {
+               while (i < tail) {
+                       if (!isspace(line[tail]))
+                               break;
+                       tail--;
+               }
        }
        if ((i < tail && line[tail + 1] != '\n')) {
                /* This has whitespace between tail+1..len */
@@ -1440,9 +1444,18 @@ struct diff_filespec *alloc_filespec(const char *path)
        memset(spec, 0, sizeof(*spec));
        spec->path = (char *)(spec + 1);
        memcpy(spec->path, path, namelen+1);
+       spec->count = 1;
        return spec;
 }
 
+void free_filespec(struct diff_filespec *spec)
+{
+       if (!--spec->count) {
+               diff_free_filespec_data(spec);
+               free(spec);
+       }
+}
+
 void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
                   unsigned short mode)
 {
@@ -1512,6 +1525,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
 static int populate_from_stdin(struct diff_filespec *s)
 {
        struct strbuf buf;
+       size_t size = 0;
 
        strbuf_init(&buf, 0);
        if (strbuf_read(&buf, 0, 0) < 0)
@@ -1519,7 +1533,8 @@ static int populate_from_stdin(struct diff_filespec *s)
                                     strerror(errno));
 
        s->should_munmap = 0;
-       s->data = strbuf_detach(&buf, &s->size);
+       s->data = strbuf_detach(&buf, &size);
+       s->size = size;
        s->should_free = 1;
        return 0;
 }
@@ -1609,9 +1624,11 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                 */
                strbuf_init(&buf, 0);
                if (convert_to_git(s->path, s->data, s->size, &buf)) {
+                       size_t size = 0;
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
-                       s->data = strbuf_detach(&buf, &s->size);
+                       s->data = strbuf_detach(&buf, &size);
+                       s->size = size;
                        s->should_free = 1;
                }
        }
@@ -1748,40 +1765,6 @@ static void remove_tempfile_on_signal(int signo)
        raise(signo);
 }
 
-static int spawn_prog(const char *pgm, const char **arg)
-{
-       pid_t pid;
-       int status;
-
-       fflush(NULL);
-       pid = fork();
-       if (pid < 0)
-               die("unable to fork");
-       if (!pid) {
-               execvp(pgm, (char *const*) arg);
-               exit(255);
-       }
-
-       while (waitpid(pid, &status, 0) < 0) {
-               if (errno == EINTR)
-                       continue;
-               return -1;
-       }
-
-       /* Earlier we did not check the exit status because
-        * diff exits non-zero if files are different, and
-        * we are not interested in knowing that.  It was a
-        * mistake which made it harder to quit a diff-*
-        * session that uses the git-apply-patch-script as
-        * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
-        * should also exit non-zero only when it wants to
-        * abort the entire diff-* session.
-        */
-       if (WIFEXITED(status) && !WEXITSTATUS(status))
-               return 0;
-       return -1;
-}
-
 /* An external diff command takes:
  *
  * diff-cmd name infile1 infile1-sha1 infile1-mode \
@@ -1834,7 +1817,8 @@ static void run_external_diff(const char *pgm,
                *arg++ = name;
        }
        *arg = NULL;
-       retval = spawn_prog(pgm, spawn_arg);
+       fflush(NULL);
+       retval = run_command_v_opt(spawn_arg, 0);
        remove_tempfile();
        if (retval) {
                fprintf(stderr, "external diff died, stopping at %s.\n", name);
@@ -2431,10 +2415,8 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
 
 void diff_free_filepair(struct diff_filepair *p)
 {
-       diff_free_filespec_data(p->one);
-       diff_free_filespec_data(p->two);
-       free(p->one);
-       free(p->two);
+       free_filespec(p->one);
+       free_filespec(p->two);
        free(p);
 }
 
@@ -2586,9 +2568,9 @@ void diff_debug_filepair(const struct diff_filepair *p, int i)
 {
        diff_debug_filespec(p->one, i, "one");
        diff_debug_filespec(p->two, i, "two");
-       fprintf(stderr, "score %d, status %c stays %d broken %d\n",
+       fprintf(stderr, "score %d, status %c rename_used %d broken %d\n",
                p->score, p->status ? p->status : '?',
-               p->source_stays, p->broken_pair);
+               p->one->rename_used, p->broken_pair);
 }
 
 void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
@@ -2606,8 +2588,8 @@ void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
 
 static void diff_resolve_rename_copy(void)
 {
-       int i, j;
-       struct diff_filepair *p, *pp;
+       int i;
+       struct diff_filepair *p;
        struct diff_queue_struct *q = &diff_queued_diff;
 
        diff_debug_queue("resolve-rename-copy", q);
@@ -2629,27 +2611,21 @@ static void diff_resolve_rename_copy(void)
                 * either in-place edit or rename/copy edit.
                 */
                else if (DIFF_PAIR_RENAME(p)) {
-                       if (p->source_stays) {
-                               p->status = DIFF_STATUS_COPIED;
-                               continue;
-                       }
-                       /* See if there is some other filepair that
-                        * copies from the same source as us.  If so
-                        * we are a copy.  Otherwise we are either a
-                        * copy if the path stays, or a rename if it
-                        * does not, but we already handled "stays" case.
+                       /*
+                        * A rename might have re-connected a broken
+                        * pair up, causing the pathnames to be the
+                        * same again. If so, that's not a rename at
+                        * all, just a modification..
+                        *
+                        * Otherwise, see if this source was used for
+                        * multiple renames, in which case we decrement
+                        * the count, and call it a copy.
                         */
-                       for (j = i + 1; j < q->nr; j++) {
-                               pp = q->queue[j];
-                               if (strcmp(pp->one->path, p->one->path))
-                                       continue; /* not us */
-                               if (!DIFF_PAIR_RENAME(pp))
-                                       continue; /* not a rename/copy */
-                               /* pp is a rename/copy from the same source */
+                       if (!strcmp(p->one->path, p->two->path))
+                               p->status = DIFF_STATUS_MODIFIED;
+                       else if (--p->one->rename_used > 0)
                                p->status = DIFF_STATUS_COPIED;
-                               break;
-                       }
-                       if (!p->status)
+                       else
                                p->status = DIFF_STATUS_RENAMED;
                }
                else if (hashcmp(p->one->sha1, p->two->sha1) ||