Fix an "implicit function definition" warning.
[gitweb.git] / builtin-apply.c
index cbe597771b42e34a2a8c0a2e88e1b7baadf7a6b4..bec95d6c8aa60ac40718f52da5a8f9603330dadb 100644 (file)
@@ -6,7 +6,6 @@
  * This applies patches on top of some (arbitrary) version of the SCM.
  *
  */
-#include <fnmatch.h>
 #include "cache.h"
 #include "cache-tree.h"
 #include "quote.h"
@@ -43,7 +42,7 @@ static int apply_verbosely;
 static int no_add;
 static int show_index_info;
 static int line_termination = '\n';
-static unsigned long p_context = -1;
+static unsigned long p_context = ULONG_MAX;
 static const char apply_usage[] =
 "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
 
@@ -140,12 +139,15 @@ struct fragment {
 struct patch {
        char *new_name, *old_name, *def_name;
        unsigned int old_mode, new_mode;
-       int is_rename, is_copy, is_new, is_delete, is_binary;
+       int is_new, is_delete;  /* -1 = unknown, 0 = false, 1 = true */
        int rejected;
        unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
-       int inaccurate_eof:1;
+       unsigned int inaccurate_eof:1;
+       unsigned int is_binary:1;
+       unsigned int is_copy:1;
+       unsigned int is_rename:1;
        struct fragment *fragments;
        char *result;
        unsigned long resultsize;
@@ -360,7 +362,7 @@ static int gitdiff_hdrend(const char *line, struct patch *patch)
 static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, const char *oldnew)
 {
        if (!orig_name && !isnull)
-               return find_name(line, NULL, 1, 0);
+               return find_name(line, NULL, 1, TERM_TAB);
 
        if (orig_name) {
                int len;
@@ -370,7 +372,7 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name,
                len = strlen(name);
                if (isnull)
                        die("git-apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
-               another = find_name(line, NULL, 1, 0);
+               another = find_name(line, NULL, 1, TERM_TAB);
                if (!another || memcmp(another, name, len))
                        die("git-apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
                free(another);
@@ -809,7 +811,8 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
                        struct fragment dummy;
                        if (parse_fragment_header(line, len, &dummy) < 0)
                                continue;
-                       error("patch fragment without header at line %d: %.*s", linenr, (int)len-1, line);
+                       die("patch fragment without header at line %d: %.*s",
+                           linenr, (int)len-1, line);
                }
 
                if (size < len + 6)
@@ -934,6 +937,7 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
                switch (*line) {
                default:
                        return -1;
+               case '\n': /* newer GNU diff, an empty context line */
                case ' ':
                        oldlines--;
                        newlines--;
@@ -1042,10 +1046,14 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
                 * then not having oldlines means the patch is creation,
                 * and not having newlines means the patch is deletion.
                 */
-               if (patch->is_new < 0 && !oldlines)
+               if (patch->is_new < 0 && !oldlines) {
                        patch->is_new = 1;
-               if (patch->is_delete < 0 && !newlines)
+                       patch->old_name = NULL;
+               }
+               if (patch->is_delete < 0 && !newlines) {
                        patch->is_delete = 1;
+                       patch->new_name = NULL;
+               }
        }
 
        if (0 < patch->is_new && oldlines)
@@ -1531,7 +1539,8 @@ static int apply_line(char *output, const char *patch, int plen)
        int need_fix_leading_space = 0;
        char *buf;
 
-       if ((new_whitespace != strip_whitespace) || !whitespace_error) {
+       if ((new_whitespace != strip_whitespace) || !whitespace_error ||
+           *patch != '+') {
                memcpy(output, patch + 1, plen);
                return plen;
        }
@@ -1623,6 +1632,14 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                                first = '-';
                }
                switch (first) {
+               case '\n':
+                       /* Newer GNU diff, empty context line */
+                       if (plen < 0)
+                               /* ... followed by '\No newline'; nothing */
+                               break;
+                       old[oldsize++] = '\n';
+                       new[newsize++] = '\n';
+                       break;
                case ' ':
                case '-':
                        memcpy(old + oldsize, patch + 1, plen);
@@ -1972,7 +1989,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
                        return error("%s: %s", old_name, strerror(errno));
 
                if (!cached)
-                       st_mode = ntohl(create_ce_mode(st.st_mode));
+                       st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode));
 
                if (patch->is_new < 0)
                        patch->is_new = 0;
@@ -2103,7 +2120,11 @@ static void numstat_patch_list(struct patch *patch)
        for ( ; patch; patch = patch->next) {
                const char *name;
                name = patch->new_name ? patch->new_name : patch->old_name;
-               printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+               if (patch->is_binary)
+                       printf("-\t-\t");
+               else
+                       printf("%d\t%d\t",
+                              patch->lines_added, patch->lines_deleted);
                if (line_termination && quote_c_style(name, NULL, NULL, 0))
                        quote_c_style(name, NULL, stdout, 0);
                else
@@ -2219,8 +2240,19 @@ static void remove_file(struct patch *patch)
                        die("unable to remove %s from index", patch->old_name);
                cache_tree_invalidate_path(active_cache_tree, patch->old_name);
        }
-       if (!cached)
-               unlink(patch->old_name);
+       if (!cached) {
+               if (!unlink(patch->old_name)) {
+                       char *name = xstrdup(patch->old_name);
+                       char *end = strrchr(name, '/');
+                       while (end) {
+                               *end = 0;
+                               if (rmdir(name))
+                                       break;
+                               end = strrchr(name, '/');
+                       }
+                       free(name);
+               }
+       }
 }
 
 static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
@@ -2558,7 +2590,7 @@ static int git_apply_config(const char *var, const char *value)
 }
 
 
-int cmd_apply(int argc, const char **argv, const char *prefix)
+int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 {
        int i;
        int read_stdin = 1;