Merge branch 'ky/imap-send'
[gitweb.git] / builtin / apply.c
index 4aa53f7fd87d5fd23c0929360b6746f48e8e3e73..8e4da2e1bdaf02590289f54750a9602281f4a365 100644 (file)
@@ -77,8 +77,7 @@ static enum ws_ignore {
 
 
 static const char *patch_input_file;
-static const char *root;
-static int root_len;
+static struct strbuf root = STRBUF_INIT;
 static int read_stdin = 1;
 static int options;
 
@@ -494,8 +493,8 @@ static char *find_name_gnu(const char *line, const char *def, int p_value)
        }
 
        strbuf_remove(&name, 0, cp - name.buf);
-       if (root)
-               strbuf_insert(&name, 0, root, root_len);
+       if (root.len)
+               strbuf_insert(&name, 0, root.buf, root.len);
        return squash_slash(strbuf_detach(&name, NULL));
 }
 
@@ -697,11 +696,8 @@ static char *find_name_common(const char *line, const char *def,
                        return squash_slash(xstrdup(def));
        }
 
-       if (root) {
-               char *ret = xmalloc(root_len + len + 1);
-               strcpy(ret, root);
-               memcpy(ret + root_len, start, len);
-               ret[root_len + len] = '\0';
+       if (root.len) {
+               char *ret = xstrfmt("%s%.*s", root.buf, len, start);
                return squash_slash(ret);
        }
 
@@ -935,22 +931,19 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name,
                return find_name(line, NULL, p_value, TERM_TAB);
 
        if (orig_name) {
-               int len;
-               const char *name;
+               int len = strlen(orig_name);
                char *another;
-               name = orig_name;
-               len = strlen(name);
                if (isnull)
-                       die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"), name, linenr);
+                       die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
+                           orig_name, linenr);
                another = find_name(line, NULL, p_value, TERM_TAB);
-               if (!another || memcmp(another, name, len + 1))
+               if (!another || memcmp(another, orig_name, len + 1))
                        die((side == DIFF_NEW_NAME) ?
                            _("git apply: bad git-diff - inconsistent new filename on line %d") :
                            _("git apply: bad git-diff - inconsistent old filename on line %d"), linenr);
                free(another);
                return orig_name;
-       }
-       else {
+       } else {
                /* expect "/dev/null" */
                if (memcmp("/dev/null", line, 9) || line[9] != '\n')
                        die(_("git apply: bad git-diff - expected /dev/null on line %d"), linenr);
@@ -960,21 +953,15 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name,
 
 static int gitdiff_oldname(const char *line, struct patch *patch)
 {
-       char *orig = patch->old_name;
        patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name,
                                              DIFF_OLD_NAME);
-       if (orig != patch->old_name)
-               free(orig);
        return 0;
 }
 
 static int gitdiff_newname(const char *line, struct patch *patch)
 {
-       char *orig = patch->new_name;
        patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name,
                                              DIFF_NEW_NAME);
-       if (orig != patch->new_name)
-               free(orig);
        return 0;
 }
 
@@ -1277,8 +1264,8 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct
         * the default name from the header.
         */
        patch->def_name = git_header_name(line, len);
-       if (patch->def_name && root) {
-               char *s = xstrfmt("%s%s", root, patch->def_name);
+       if (patch->def_name && root.len) {
+               char *s = xstrfmt("%s%s", root.buf, patch->def_name);
                free(patch->def_name);
                patch->def_name = s;
        }
@@ -1876,6 +1863,11 @@ static struct fragment *parse_binary_hunk(char **buf_p,
        return NULL;
 }
 
+/*
+ * Returns:
+ *   -1 in case of error,
+ *   the length of the parsed binary patch otherwise
+ */
 static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
 {
        /*
@@ -2021,6 +2013,8 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
                        linenr++;
                        used = parse_binary(buffer + hd + llen,
                                            size - hd - llen, patch);
+                       if (used < 0)
+                               return -1;
                        if (used)
                                patchsize = used + llen;
                        else
@@ -2636,7 +2630,7 @@ static void update_image(struct image *img,
        insert_count = postimage->len;
 
        /* Adjust the contents */
-       result = xmalloc(img->len + insert_count - remove_count + 1);
+       result = xmalloc(st_add3(st_sub(img->len, remove_count), insert_count, 1));
        memcpy(result, img->buf, applied_at);
        memcpy(result + applied_at, postimage->buf, postimage->len);
        memcpy(result + applied_at + postimage->len,
@@ -4377,8 +4371,10 @@ static int apply_patch(int fd, const char *filename, int options)
                patch->inaccurate_eof = !!(options & INACCURATE_EOF);
                patch->recount =  !!(options & RECOUNT);
                nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
-               if (nr < 0)
+               if (nr < 0) {
+                       free_patch(patch);
                        break;
+               }
                if (apply_in_reverse)
                        reverse_patches(patch);
                if (use_patch(patch)) {
@@ -4387,6 +4383,8 @@ static int apply_patch(int fd, const char *filename, int options)
                        listp = &patch->next;
                }
                else {
+                       if (apply_verbosely)
+                               say_patch_name(stderr, _("Skipped patch '%s'."), patch);
                        free_patch(patch);
                        skipped_patch++;
                }
@@ -4468,16 +4466,6 @@ static int option_parse_p(const struct option *opt,
        return 0;
 }
 
-static int option_parse_z(const struct option *opt,
-                         const char *arg, int unset)
-{
-       if (unset)
-               line_termination = '\n';
-       else
-               line_termination = 0;
-       return 0;
-}
-
 static int option_parse_space_change(const struct option *opt,
                          const char *arg, int unset)
 {
@@ -4501,14 +4489,9 @@ static int option_parse_whitespace(const struct option *opt,
 static int option_parse_directory(const struct option *opt,
                                  const char *arg, int unset)
 {
-       root_len = strlen(arg);
-       if (root_len && arg[root_len - 1] != '/') {
-               char *new_root;
-               root = new_root = xmalloc(root_len + 2);
-               strcpy(new_root, arg);
-               strcpy(new_root + root_len++, "/");
-       } else
-               root = arg;
+       strbuf_reset(&root);
+       strbuf_addstr(&root, arg);
+       strbuf_complete(&root, '/');
        return 0;
 }
 
@@ -4555,9 +4538,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                         N_( "attempt three-way merge if a patch does not apply")),
                OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
                        N_("build a temporary index based on embedded index information")),
-               { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
-                       N_("paths are separated with NUL character"),
-                       PARSE_OPT_NOARG, option_parse_z },
+               /* Think twice before adding "--nul" synonym to this */
+               OPT_SET_INT('z', NULL, &line_termination,
+                       N_("paths are separated with NUL character"), '\0'),
                OPT_INTEGER('C', NULL, &p_context,
                                N_("ensure at least <n> lines of context match")),
                { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"),