git.el: Always set the current directory in the git-diff buffer.
[gitweb.git] / builtin-apply.c
index 0399743c4e2288a0812faeea92c07a5f6a13fccc..da270755a7b9ecafa3cb47d9f6947c6dc5b2531c 100644 (file)
@@ -55,7 +55,7 @@ static enum whitespace_eol {
 } new_whitespace = warn_on_whitespace;
 static int whitespace_error;
 static int squelch_whitespace_errors = 5;
-static int applied_after_stripping;
+static int applied_after_fixing_ws;
 static const char *patch_input_file;
 
 static void parse_whitespace_option(const char *option)
@@ -1003,12 +1003,16 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
                        trailing++;
                        break;
                case '-':
+                       if (apply_in_reverse &&
+                                       new_whitespace != nowarn_whitespace)
+                               check_whitespace(line, len);
                        deleted++;
                        oldlines--;
                        trailing = 0;
                        break;
                case '+':
-                       if (new_whitespace != nowarn_whitespace)
+                       if (!apply_in_reverse &&
+                                       new_whitespace != nowarn_whitespace)
                                check_whitespace(line, len);
                        added++;
                        newlines--;
@@ -1657,7 +1661,7 @@ static int apply_line(char *output, const char *patch, int plen)
        if (add_nl_to_tail)
                output[plen++] = '\n';
        if (fixed)
-               applied_after_stripping++;
+               applied_after_fixing_ws++;
        return output + plen - buf;
 }
 
@@ -1671,6 +1675,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
        char *new = xmalloc(size);
        const char *oldlines, *newlines;
        int oldsize = 0, newsize = 0;
+       int new_blank_lines_at_end = 0;
        unsigned long leading, trailing;
        int pos, lines;
 
@@ -1678,6 +1683,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                char first;
                int len = linelen(patch, size);
                int plen;
+               int added_blank_line = 0;
 
                if (!len)
                        break;
@@ -1699,6 +1705,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                        else if (first == '+')
                                first = '-';
                }
+
                switch (first) {
                case '\n':
                        /* Newer GNU diff, empty context line */
@@ -1716,9 +1723,14 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                                break;
                /* Fall-through for ' ' */
                case '+':
-                       if (first != '+' || !no_add)
-                               newsize += apply_line(new + newsize, patch,
-                                                     plen);
+                       if (first != '+' || !no_add) {
+                               int added = apply_line(new + newsize, patch,
+                                                      plen);
+                               newsize += added;
+                               if (first == '+' &&
+                                   added == 1 && new[newsize-1] == '\n')
+                                       added_blank_line = 1;
+                       }
                        break;
                case '@': case '\\':
                        /* Ignore it, we already handled it */
@@ -1728,6 +1740,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                                error("invalid start of line: '%c'", first);
                        return -1;
                }
+               if (added_blank_line)
+                       new_blank_lines_at_end++;
+               else
+                       new_blank_lines_at_end = 0;
                patch += len;
                size -= len;
        }
@@ -1770,9 +1786,16 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                if (match_beginning && offset)
                        offset = -1;
                if (offset >= 0) {
-                       int diff = newsize - oldsize;
-                       unsigned long size = desc->size + diff;
-                       unsigned long alloc = desc->alloc;
+                       int diff;
+                       unsigned long size, alloc;
+
+                       if (new_whitespace == strip_whitespace &&
+                           (desc->size - oldsize - offset == 0)) /* end of file? */
+                               newsize -= new_blank_lines_at_end;
+
+                       diff = newsize - oldsize;
+                       size = desc->size + diff;
+                       alloc = desc->alloc;
 
                        /* Warn if it was necessary to reduce the number
                         * of context lines.
@@ -2485,7 +2508,7 @@ static void write_out_one_result(struct patch *patch, int phase)
         * thing: remove the old, write the new
         */
        if (phase == 0)
-               remove_file(patch, 0);
+               remove_file(patch, patch->is_rename);
        if (phase == 1)
                create_file(patch);
 }
@@ -2865,18 +2888,17 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                                squelched == 1 ? "" : "s");
                }
                if (new_whitespace == error_on_whitespace)
-                       die("%d line%s add%s trailing whitespaces.",
+                       die("%d line%s add%s whitespace errors.",
                            whitespace_error,
                            whitespace_error == 1 ? "" : "s",
                            whitespace_error == 1 ? "s" : "");
-               if (applied_after_stripping)
+               if (applied_after_fixing_ws)
                        fprintf(stderr, "warning: %d line%s applied after"
-                               " stripping trailing whitespaces.\n",
-                               applied_after_stripping,
-                               applied_after_stripping == 1 ? "" : "s");
+                               " fixing whitespace errors.\n",
+                               applied_after_fixing_ws,
+                               applied_after_fixing_ws == 1 ? "" : "s");
                else if (whitespace_error)
-                       fprintf(stderr, "warning: %d line%s add%s trailing"
-                               " whitespaces.\n",
+                       fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n",
                                whitespace_error,
                                whitespace_error == 1 ? "" : "s",
                                whitespace_error == 1 ? "s" : "");