Merge branch 'jc/advise-i18n'
[gitweb.git] / builtin / apply.c
index 3af4ae0c269bc8a2cb1bb4240af1f191d2ba0442..c24dc546d0cc3f223c40c12aa20dc75eff13d4f9 100644 (file)
@@ -43,6 +43,7 @@ static int apply = 1;
 static int apply_in_reverse;
 static int apply_with_reject;
 static int apply_verbosely;
+static int allow_overlap;
 static int no_add;
 static const char *fake_ancestor;
 static int line_termination = '\n';
@@ -56,7 +57,7 @@ static enum ws_error_action {
        nowarn_ws_error,
        warn_on_ws_error,
        die_on_ws_error,
-       correct_ws_error,
+       correct_ws_error
 } ws_error_action = warn_on_ws_error;
 static int whitespace_error;
 static int squelch_whitespace_errors = 5;
@@ -64,7 +65,7 @@ static int applied_after_fixing_ws;
 
 static enum ws_ignore {
        ignore_ws_none,
-       ignore_ws_change,
+       ignore_ws_change
 } ws_ignore_action = ignore_ws_none;
 
 
@@ -204,6 +205,7 @@ struct line {
        unsigned hash : 24;
        unsigned flag : 8;
 #define LINE_COMMON     1
+#define LINE_PATCHED   2
 };
 
 /*
@@ -248,9 +250,6 @@ static int fuzzy_matchlines(const char *s1, size_t n1,
        const char *last2 = s2 + n2 - 1;
        int result = 0;
 
-       if (n1 < 0 || n2 < 0)
-               return 0;
-
        /* ignore line endings */
        while ((*last1 == '\r') || (*last1 == '\n'))
                last1--;
@@ -416,48 +415,210 @@ static char *squash_slash(char *name)
        return name;
 }
 
-static char *find_name(const char *line, char *def, int p_value, int terminate)
+static char *find_name_gnu(const char *line, char *def, int p_value)
 {
-       int len;
-       const char *start = NULL;
+       struct strbuf name = STRBUF_INIT;
+       char *cp;
 
-       if (p_value == 0)
-               start = line;
+       /*
+        * Proposed "new-style" GNU patch/diff format; see
+        * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
+        */
+       if (unquote_c_style(&name, line, NULL)) {
+               strbuf_release(&name);
+               return NULL;
+       }
 
-       if (*line == '"') {
-               struct strbuf name = STRBUF_INIT;
+       for (cp = name.buf; p_value; p_value--) {
+               cp = strchr(cp, '/');
+               if (!cp) {
+                       strbuf_release(&name);
+                       return NULL;
+               }
+               cp++;
+       }
 
-               /*
-                * Proposed "new-style" GNU patch/diff format; see
-                * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
-                */
-               if (!unquote_c_style(&name, line, NULL)) {
-                       char *cp;
+       /* name can later be freed, so we need
+        * to memmove, not just return cp
+        */
+       strbuf_remove(&name, 0, cp - name.buf);
+       free(def);
+       if (root)
+               strbuf_insert(&name, 0, root, root_len);
+       return squash_slash(strbuf_detach(&name, NULL));
+}
 
-                       for (cp = name.buf; p_value; p_value--) {
-                               cp = strchr(cp, '/');
-                               if (!cp)
-                                       break;
-                               cp++;
-                       }
-                       if (cp) {
-                               /* name can later be freed, so we need
-                                * to memmove, not just return cp
-                                */
-                               strbuf_remove(&name, 0, cp - name.buf);
-                               free(def);
-                               if (root)
-                                       strbuf_insert(&name, 0, root, root_len);
-                               return squash_slash(strbuf_detach(&name, NULL));
-                       }
-               }
-               strbuf_release(&name);
+static size_t sane_tz_len(const char *line, size_t len)
+{
+       const char *tz, *p;
+
+       if (len < strlen(" +0500") || line[len-strlen(" +0500")] != ' ')
+               return 0;
+       tz = line + len - strlen(" +0500");
+
+       if (tz[1] != '+' && tz[1] != '-')
+               return 0;
+
+       for (p = tz + 2; p != line + len; p++)
+               if (!isdigit(*p))
+                       return 0;
+
+       return line + len - tz;
+}
+
+static size_t tz_with_colon_len(const char *line, size_t len)
+{
+       const char *tz, *p;
+
+       if (len < strlen(" +08:00") || line[len - strlen(":00")] != ':')
+               return 0;
+       tz = line + len - strlen(" +08:00");
+
+       if (tz[0] != ' ' || (tz[1] != '+' && tz[1] != '-'))
+               return 0;
+       p = tz + 2;
+       if (!isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+           !isdigit(*p++) || !isdigit(*p++))
+               return 0;
+
+       return line + len - tz;
+}
+
+static size_t date_len(const char *line, size_t len)
+{
+       const char *date, *p;
+
+       if (len < strlen("72-02-05") || line[len-strlen("-05")] != '-')
+               return 0;
+       p = date = line + len - strlen("72-02-05");
+
+       if (!isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+           !isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+           !isdigit(*p++) || !isdigit(*p++))   /* Not a date. */
+               return 0;
+
+       if (date - line >= strlen("19") &&
+           isdigit(date[-1]) && isdigit(date[-2]))     /* 4-digit year */
+               date -= strlen("19");
+
+       return line + len - date;
+}
+
+static size_t short_time_len(const char *line, size_t len)
+{
+       const char *time, *p;
+
+       if (len < strlen(" 07:01:32") || line[len-strlen(":32")] != ':')
+               return 0;
+       p = time = line + len - strlen(" 07:01:32");
+
+       /* Permit 1-digit hours? */
+       if (*p++ != ' ' ||
+           !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+           !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+           !isdigit(*p++) || !isdigit(*p++))   /* Not a time. */
+               return 0;
+
+       return line + len - time;
+}
+
+static size_t fractional_time_len(const char *line, size_t len)
+{
+       const char *p;
+       size_t n;
+
+       /* Expected format: 19:41:17.620000023 */
+       if (!len || !isdigit(line[len - 1]))
+               return 0;
+       p = line + len - 1;
+
+       /* Fractional seconds. */
+       while (p > line && isdigit(*p))
+               p--;
+       if (*p != '.')
+               return 0;
+
+       /* Hours, minutes, and whole seconds. */
+       n = short_time_len(line, p - line);
+       if (!n)
+               return 0;
+
+       return line + len - p + n;
+}
+
+static size_t trailing_spaces_len(const char *line, size_t len)
+{
+       const char *p;
+
+       /* Expected format: ' ' x (1 or more)  */
+       if (!len || line[len - 1] != ' ')
+               return 0;
+
+       p = line + len;
+       while (p != line) {
+               p--;
+               if (*p != ' ')
+                       return line + len - (p + 1);
        }
 
-       for (;;) {
+       /* All spaces! */
+       return len;
+}
+
+static size_t diff_timestamp_len(const char *line, size_t len)
+{
+       const char *end = line + len;
+       size_t n;
+
+       /*
+        * Posix: 2010-07-05 19:41:17
+        * GNU: 2010-07-05 19:41:17.620000023 -0500
+        */
+
+       if (!isdigit(end[-1]))
+               return 0;
+
+       n = sane_tz_len(line, end - line);
+       if (!n)
+               n = tz_with_colon_len(line, end - line);
+       end -= n;
+
+       n = short_time_len(line, end - line);
+       if (!n)
+               n = fractional_time_len(line, end - line);
+       end -= n;
+
+       n = date_len(line, end - line);
+       if (!n) /* No date.  Too bad. */
+               return 0;
+       end -= n;
+
+       if (end == line)        /* No space before date. */
+               return 0;
+       if (end[-1] == '\t') {  /* Success! */
+               end--;
+               return line + len - end;
+       }
+       if (end[-1] != ' ')     /* No space before date. */
+               return 0;
+
+       /* Whitespace damage. */
+       end -= trailing_spaces_len(line, end - line);
+       return line + len - end;
+}
+
+static char *find_name_common(const char *line, char *def, int p_value,
+                               const char *end, int terminate)
+{
+       int len;
+       const char *start = NULL;
+
+       if (p_value == 0)
+               start = line;
+       while (line != end) {
                char c = *line;
 
-               if (isspace(c)) {
+               if (!end && isspace(c)) {
                        if (c == '\n')
                                break;
                        if (name_terminate(start, line-start, c, terminate))
@@ -497,6 +658,37 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
        return squash_slash(xmemdupz(start, len));
 }
 
+static char *find_name(const char *line, char *def, int p_value, int terminate)
+{
+       if (*line == '"') {
+               char *name = find_name_gnu(line, def, p_value);
+               if (name)
+                       return name;
+       }
+
+       return find_name_common(line, def, p_value, NULL, terminate);
+}
+
+static char *find_name_traditional(const char *line, char *def, int p_value)
+{
+       size_t len = strlen(line);
+       size_t date_len;
+
+       if (*line == '"') {
+               char *name = find_name_gnu(line, def, p_value);
+               if (name)
+                       return name;
+       }
+
+       len = strchrnul(line, '\n') - line;
+       date_len = diff_timestamp_len(line, len);
+       if (!date_len)
+               return find_name_common(line, def, p_value, NULL, TERM_TAB);
+       len -= date_len;
+
+       return find_name_common(line, def, p_value, line + len, 0);
+}
+
 static int count_slashes(const char *cp)
 {
        int cnt = 0;
@@ -519,7 +711,7 @@ static int guess_p_value(const char *nameline)
 
        if (is_dev_null(nameline))
                return -1;
-       name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
+       name = find_name_traditional(nameline, NULL, 0);
        if (!name)
                return -1;
        cp = strchr(name, '/');
@@ -560,8 +752,8 @@ static int has_epoch_timestamp(const char *nameline)
                " "
                "[0-2][0-9]:[0-5][0-9]:00(\\.0+)?"
                " "
-               "([-+][0-2][0-9][0-5][0-9])\n";
-       const char *timestamp = NULL, *cp;
+               "([-+][0-2][0-9]:?[0-5][0-9])\n";
+       const char *timestamp = NULL, *cp, *colon;
        static regex_t *stamp;
        regmatch_t m[10];
        int zoneoffset;
@@ -591,8 +783,11 @@ static int has_epoch_timestamp(const char *nameline)
                return 0;
        }
 
-       zoneoffset = strtol(timestamp + m[3].rm_so + 1, NULL, 10);
-       zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
+       zoneoffset = strtol(timestamp + m[3].rm_so + 1, (char **) &colon, 10);
+       if (*colon == ':')
+               zoneoffset = zoneoffset * 60 + strtol(colon + 1, NULL, 10);
+       else
+               zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
        if (timestamp[m[3].rm_so] == '-')
                zoneoffset = -zoneoffset;
 
@@ -638,16 +833,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
        if (is_dev_null(first)) {
                patch->is_new = 1;
                patch->is_delete = 0;
-               name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB);
+               name = find_name_traditional(second, NULL, p_value);
                patch->new_name = name;
        } else if (is_dev_null(second)) {
                patch->is_new = 0;
                patch->is_delete = 1;
-               name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
+               name = find_name_traditional(first, NULL, p_value);
                patch->old_name = name;
        } else {
-               name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
-               name = find_name(second, name, p_value, TERM_SPACE | TERM_TAB);
+               name = find_name_traditional(first, NULL, p_value);
+               name = find_name_traditional(second, name, p_value);
                if (has_epoch_timestamp(first)) {
                        patch->is_new = 1;
                        patch->is_delete = 0;
@@ -746,28 +941,28 @@ static int gitdiff_newfile(const char *line, struct patch *patch)
 static int gitdiff_copysrc(const char *line, struct patch *patch)
 {
        patch->is_copy = 1;
-       patch->old_name = find_name(line, NULL, 0, 0);
+       patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
        return 0;
 }
 
 static int gitdiff_copydst(const char *line, struct patch *patch)
 {
        patch->is_copy = 1;
-       patch->new_name = find_name(line, NULL, 0, 0);
+       patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
        return 0;
 }
 
 static int gitdiff_renamesrc(const char *line, struct patch *patch)
 {
        patch->is_rename = 1;
-       patch->old_name = find_name(line, NULL, 0, 0);
+       patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
        return 0;
 }
 
 static int gitdiff_renamedst(const char *line, struct patch *patch)
 {
        patch->is_rename = 1;
-       patch->new_name = find_name(line, NULL, 0, 0);
+       patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
        return 0;
 }
 
@@ -852,7 +1047,7 @@ static char *git_header_name(char *line, int llen)
 {
        const char *name;
        const char *second = NULL;
-       size_t len;
+       size_t len, line_len;
 
        line += strlen("diff --git ");
        llen -= strlen("diff --git ");
@@ -952,6 +1147,10 @@ static char *git_header_name(char *line, int llen)
         * Accept a name only if it shows up twice, exactly the same
         * form.
         */
+       second = strchr(name, '\n');
+       if (!second)
+               return NULL;
+       line_len = second - name;
        for (len = 0 ; ; len++) {
                switch (name[len]) {
                default:
@@ -959,15 +1158,11 @@ static char *git_header_name(char *line, int llen)
                case '\n':
                        return NULL;
                case '\t': case ' ':
-                       second = name+len;
-                       for (;;) {
-                               char c = *second++;
-                               if (c == '\n')
-                                       return NULL;
-                               if (c == '/')
-                                       break;
-                       }
-                       if (second[len] == '\n' && !memcmp(name, second, len)) {
+                       second = stop_at_slash(name + len, line_len - len);
+                       if (!second)
+                               return NULL;
+                       second++;
+                       if (second[len] == '\n' && !strncmp(name, second, len)) {
                                return xmemdupz(name, len);
                        }
                }
@@ -1209,6 +1404,9 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
                                            "%d leading pathname components (line %d)" , p_value, linenr);
                                patch->old_name = patch->new_name = patch->def_name;
                        }
+                       if (!patch->is_delete && !patch->new_name)
+                               die("git diff header lacks filename information "
+                                   "(line %d)", linenr);
                        patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
@@ -1436,7 +1634,7 @@ static inline int metadata_changes(struct patch *patch)
 static char *inflate_it(const void *data, unsigned long size,
                        unsigned long inflated_size)
 {
-       z_stream stream;
+       git_zstream stream;
        void *out;
        int st;
 
@@ -1854,33 +2052,79 @@ static int match_fragment(struct image *img,
 {
        int i;
        char *fixed_buf, *buf, *orig, *target;
+       struct strbuf fixed;
+       size_t fixed_len;
+       int preimage_limit;
 
-       if (preimage->nr + try_lno > img->nr)
+       if (preimage->nr + try_lno <= img->nr) {
+               /*
+                * The hunk falls within the boundaries of img.
+                */
+               preimage_limit = preimage->nr;
+               if (match_end && (preimage->nr + try_lno != img->nr))
+                       return 0;
+       } else if (ws_error_action == correct_ws_error &&
+                  (ws_rule & WS_BLANK_AT_EOF)) {
+               /*
+                * This hunk extends beyond the end of img, and we are
+                * removing blank lines at the end of the file.  This
+                * many lines from the beginning of the preimage must
+                * match with img, and the remainder of the preimage
+                * must be blank.
+                */
+               preimage_limit = img->nr - try_lno;
+       } else {
+               /*
+                * The hunk extends beyond the end of the img and
+                * we are not removing blanks at the end, so we
+                * should reject the hunk at this position.
+                */
                return 0;
+       }
 
        if (match_beginning && try_lno)
                return 0;
 
-       if (match_end && preimage->nr + try_lno != img->nr)
-               return 0;
-
        /* Quick hash check */
-       for (i = 0; i < preimage->nr; i++)
-               if (preimage->line[i].hash != img->line[try_lno + i].hash)
+       for (i = 0; i < preimage_limit; i++)
+               if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
+                   (preimage->line[i].hash != img->line[try_lno + i].hash))
                        return 0;
 
-       /*
-        * Do we have an exact match?  If we were told to match
-        * at the end, size must be exactly at try+fragsize,
-        * otherwise try+fragsize must be still within the preimage,
-        * and either case, the old piece should match the preimage
-        * exactly.
-        */
-       if ((match_end
-            ? (try + preimage->len == img->len)
-            : (try + preimage->len <= img->len)) &&
-           !memcmp(img->buf + try, preimage->buf, preimage->len))
-               return 1;
+       if (preimage_limit == preimage->nr) {
+               /*
+                * Do we have an exact match?  If we were told to match
+                * at the end, size must be exactly at try+fragsize,
+                * otherwise try+fragsize must be still within the preimage,
+                * and either case, the old piece should match the preimage
+                * exactly.
+                */
+               if ((match_end
+                    ? (try + preimage->len == img->len)
+                    : (try + preimage->len <= img->len)) &&
+                   !memcmp(img->buf + try, preimage->buf, preimage->len))
+                       return 1;
+       } else {
+               /*
+                * The preimage extends beyond the end of img, so
+                * there cannot be an exact match.
+                *
+                * There must be one non-blank context line that match
+                * a line before the end of img.
+                */
+               char *buf_end;
+
+               buf = preimage->buf;
+               buf_end = buf;
+               for (i = 0; i < preimage_limit; i++)
+                       buf_end += preimage->line[i].len;
+
+               for ( ; buf < buf_end; buf++)
+                       if (!isspace(*buf))
+                               break;
+               if (buf == buf_end)
+                       return 0;
+       }
 
        /*
         * No exact match. If we are ignoring whitespace, run a line-by-line
@@ -1891,7 +2135,10 @@ static int match_fragment(struct image *img,
                size_t imgoff = 0;
                size_t preoff = 0;
                size_t postlen = postimage->len;
-               for (i = 0; i < preimage->nr; i++) {
+               size_t extra_chars;
+               char *preimage_eof;
+               char *preimage_end;
+               for (i = 0; i < preimage_limit; i++) {
                        size_t prelen = preimage->line[i].len;
                        size_t imglen = img->line[try_lno+i].len;
 
@@ -1905,22 +2152,38 @@ static int match_fragment(struct image *img,
                }
 
                /*
-                * Ok, the preimage matches with whitespace fuzz. Update it and
-                * the common postimage lines to use the same whitespace as the
-                * target. imgoff now holds the true length of the target that
-                * matches the preimage, and we need to update the line lengths
-                * of the preimage to match the target ones.
+                * Ok, the preimage matches with whitespace fuzz.
+                *
+                * imgoff now holds the true length of the target that
+                * matches the preimage before the end of the file.
+                *
+                * Count the number of characters in the preimage that fall
+                * beyond the end of the file and make sure that all of them
+                * are whitespace characters. (This can only happen if
+                * we are removing blank lines at the end of the file.)
                 */
-               fixed_buf = xmalloc(imgoff);
-               memcpy(fixed_buf, img->buf + try, imgoff);
-               for (i = 0; i < preimage->nr; i++)
-                       preimage->line[i].len = img->line[try_lno+i].len;
+               buf = preimage_eof = preimage->buf + preoff;
+               for ( ; i < preimage->nr; i++)
+                       preoff += preimage->line[i].len;
+               preimage_end = preimage->buf + preoff;
+               for ( ; buf < preimage_end; buf++)
+                       if (!isspace(*buf))
+                               return 0;
 
                /*
-                * Update the preimage buffer and the postimage context lines.
+                * Update the preimage and the common postimage context
+                * lines to use the same whitespace as the target.
+                * If whitespace is missing in the target (i.e.
+                * if the preimage extends beyond the end of the file),
+                * use the whitespace from the preimage.
                 */
+               extra_chars = preimage_end - preimage_eof;
+               strbuf_init(&fixed, imgoff + extra_chars);
+               strbuf_add(&fixed, img->buf + try, imgoff);
+               strbuf_add(&fixed, preimage_eof, extra_chars);
+               fixed_buf = strbuf_detach(&fixed, &fixed_len);
                update_pre_post_images(preimage, postimage,
-                               fixed_buf, imgoff, postlen);
+                               fixed_buf, fixed_len, postlen);
                return 1;
        }
 
@@ -1932,28 +2195,27 @@ static int match_fragment(struct image *img,
         * it might with whitespace fuzz. We haven't been asked to
         * ignore whitespace, we were asked to correct whitespace
         * errors, so let's try matching after whitespace correction.
+        *
+        * The preimage may extend beyond the end of the file,
+        * but in this loop we will only handle the part of the
+        * preimage that falls within the file.
         */
-       fixed_buf = xmalloc(preimage->len + 1);
-       buf = fixed_buf;
+       strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
        target = img->buf + try;
-       for (i = 0; i < preimage->nr; i++) {
-               size_t fixlen; /* length after fixing the preimage */
+       for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
                size_t tgtlen = img->line[try_lno + i].len;
-               size_t tgtfixlen; /* length after fixing the target line */
-               char tgtfixbuf[1024], *tgtfix;
+               size_t fixstart = fixed.len;
+               struct strbuf tgtfix;
                int match;
 
                /* Try fixing the line in the preimage */
-               fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
+               ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
 
                /* Try fixing the line in the target */
-               if (sizeof(tgtfixbuf) > tgtlen)
-                       tgtfix = tgtfixbuf;
-               else
-                       tgtfix = xmalloc(tgtlen);
-               tgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL);
+               strbuf_init(&tgtfix, tgtlen);
+               ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
 
                /*
                 * If they match, either the preimage was based on
@@ -1965,29 +2227,52 @@ static int match_fragment(struct image *img,
                 * so we might as well take the fix together with their
                 * real change.
                 */
-               match = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen));
+               match = (tgtfix.len == fixed.len - fixstart &&
+                        !memcmp(tgtfix.buf, fixed.buf + fixstart,
+                                            fixed.len - fixstart));
 
-               if (tgtfix != tgtfixbuf)
-                       free(tgtfix);
+               strbuf_release(&tgtfix);
                if (!match)
                        goto unmatch_exit;
 
                orig += oldlen;
-               buf += fixlen;
                target += tgtlen;
        }
 
+
+       /*
+        * Now handle the lines in the preimage that falls beyond the
+        * end of the file (if any). They will only match if they are
+        * empty or only contain whitespace (if WS_BLANK_AT_EOL is
+        * false).
+        */
+       for ( ; i < preimage->nr; i++) {
+               size_t fixstart = fixed.len; /* start of the fixed preimage */
+               size_t oldlen = preimage->line[i].len;
+               int j;
+
+               /* Try fixing the line in the preimage */
+               ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
+
+               for (j = fixstart; j < fixed.len; j++)
+                       if (!isspace(fixed.buf[j]))
+                               goto unmatch_exit;
+
+               orig += oldlen;
+       }
+
        /*
         * Yes, the preimage is based on an older version that still
         * has whitespace breakages unfixed, and fixing them makes the
         * hunk match.  Update the context lines in the postimage.
         */
+       fixed_buf = strbuf_detach(&fixed, &fixed_len);
        update_pre_post_images(preimage, postimage,
-                              fixed_buf, buf - fixed_buf, 0);
+                              fixed_buf, fixed_len, 0);
        return 1;
 
  unmatch_exit:
-       free(fixed_buf);
+       strbuf_release(&fixed);
        return 0;
 }
 
@@ -2002,9 +2287,6 @@ static int find_pos(struct image *img,
        unsigned long backwards, forwards, try;
        int backwards_lno, forwards_lno, try_lno;
 
-       if (preimage->nr > img->nr)
-               return -1;
-
        /*
         * If match_beginning or match_end is specified, there is no
         * point starting from a wrong line that will never match and
@@ -2015,7 +2297,12 @@ static int find_pos(struct image *img,
        else if (match_end)
                line = img->nr - preimage->nr;
 
-       if (line > img->nr)
+       /*
+        * Because the comparison is unsigned, the following test
+        * will also take care of a negative line number that can
+        * result when match_end and preimage is larger than the target.
+        */
+       if ((size_t) line > img->nr)
                line = img->nr;
 
        try = 0;
@@ -2091,12 +2378,26 @@ static void update_image(struct image *img,
        int i, nr;
        size_t remove_count, insert_count, applied_at = 0;
        char *result;
+       int preimage_limit;
+
+       /*
+        * If we are removing blank lines at the end of img,
+        * the preimage may extend beyond the end.
+        * If that is the case, we must be careful only to
+        * remove the part of the preimage that falls within
+        * the boundaries of img. Initialize preimage_limit
+        * to the number of lines in the preimage that falls
+        * within the boundaries.
+        */
+       preimage_limit = preimage->nr;
+       if (preimage_limit > img->nr - applied_pos)
+               preimage_limit = img->nr - applied_pos;
 
        for (i = 0; i < applied_pos; i++)
                applied_at += img->line[i].len;
 
        remove_count = 0;
-       for (i = 0; i < preimage->nr; i++)
+       for (i = 0; i < preimage_limit; i++)
                remove_count += img->line[applied_pos + i].len;
        insert_count = postimage->len;
 
@@ -2113,8 +2414,8 @@ static void update_image(struct image *img,
        result[img->len] = '\0';
 
        /* Adjust the line table */
-       nr = img->nr + postimage->nr - preimage->nr;
-       if (preimage->nr < postimage->nr) {
+       nr = img->nr + postimage->nr - preimage_limit;
+       if (preimage_limit < postimage->nr) {
                /*
                 * NOTE: this knows that we never call remove_first_line()
                 * on anything other than pre/post image.
@@ -2122,25 +2423,32 @@ static void update_image(struct image *img,
                img->line = xrealloc(img->line, nr * sizeof(*img->line));
                img->line_allocated = img->line;
        }
-       if (preimage->nr != postimage->nr)
+       if (preimage_limit != postimage->nr)
                memmove(img->line + applied_pos + postimage->nr,
-                       img->line + applied_pos + preimage->nr,
-                       (img->nr - (applied_pos + preimage->nr)) *
+                       img->line + applied_pos + preimage_limit,
+                       (img->nr - (applied_pos + preimage_limit)) *
                        sizeof(*img->line));
        memcpy(img->line + applied_pos,
               postimage->line,
               postimage->nr * sizeof(*img->line));
+       if (!allow_overlap)
+               for (i = 0; i < postimage->nr; i++)
+                       img->line[applied_pos + i].flag |= LINE_PATCHED;
        img->nr = nr;
 }
 
 static int apply_one_fragment(struct image *img, struct fragment *frag,
-                             int inaccurate_eof, unsigned ws_rule)
+                             int inaccurate_eof, unsigned ws_rule,
+                             int nth_fragment)
 {
        int match_beginning, match_end;
        const char *patch = frag->patch;
        int size = frag->size;
-       char *old, *new, *oldlines, *newlines;
+       char *old, *oldlines;
+       struct strbuf newlines;
        int new_blank_lines_at_end = 0;
+       int found_new_blank_lines_at_end = 0;
+       int hunk_linenr = frag->linenr;
        unsigned long leading, trailing;
        int pos, applied_pos;
        struct image preimage;
@@ -2149,16 +2457,16 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
        memset(&preimage, 0, sizeof(preimage));
        memset(&postimage, 0, sizeof(postimage));
        oldlines = xmalloc(size);
-       newlines = xmalloc(size);
+       strbuf_init(&newlines, size);
 
        old = oldlines;
-       new = newlines;
        while (size > 0) {
                char first;
                int len = linelen(patch, size);
-               int plen, added;
+               int plen;
                int added_blank_line = 0;
                int is_blank_context = 0;
+               size_t start;
 
                if (!len)
                        break;
@@ -2188,7 +2496,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                                /* ... followed by '\No newline'; nothing */
                                break;
                        *old++ = '\n';
-                       *new++ = '\n';
+                       strbuf_addch(&newlines, '\n');
                        add_line_info(&preimage, "\n", 1, LINE_COMMON);
                        add_line_info(&postimage, "\n", 1, LINE_COMMON);
                        is_blank_context = 1;
@@ -2210,18 +2518,17 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                        if (first == '+' && no_add)
                                break;
 
+                       start = newlines.len;
                        if (first != '+' ||
                            !whitespace_error ||
                            ws_error_action != correct_ws_error) {
-                               memcpy(new, patch + 1, plen);
-                               added = plen;
+                               strbuf_add(&newlines, patch + 1, plen);
                        }
                        else {
-                               added = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
+                               ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
                        }
-                       add_line_info(&postimage, new, added,
+                       add_line_info(&postimage, newlines.buf + start, newlines.len - start,
                                      (first == '+' ? 0 : LINE_COMMON));
-                       new += added;
                        if (first == '+' &&
                            (ws_rule & WS_BLANK_AT_EOF) &&
                            ws_blank_line(patch + 1, plen, ws_rule))
@@ -2235,20 +2542,24 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                                error("invalid start of line: '%c'", first);
                        return -1;
                }
-               if (added_blank_line)
+               if (added_blank_line) {
+                       if (!new_blank_lines_at_end)
+                               found_new_blank_lines_at_end = hunk_linenr;
                        new_blank_lines_at_end++;
+               }
                else if (is_blank_context)
                        ;
                else
                        new_blank_lines_at_end = 0;
                patch += len;
                size -= len;
+               hunk_linenr++;
        }
        if (inaccurate_eof &&
            old > oldlines && old[-1] == '\n' &&
-           new > newlines && new[-1] == '\n') {
+           newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
                old--;
-               new--;
+               strbuf_setlen(&newlines, newlines.len - 1);
        }
 
        leading = frag->leading;
@@ -2280,8 +2591,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
        pos = frag->newpos ? (frag->newpos - 1) : 0;
        preimage.buf = oldlines;
        preimage.len = old - oldlines;
-       postimage.buf = newlines;
-       postimage.len = new - newlines;
+       postimage.buf = newlines.buf;
+       postimage.len = newlines.len;
        preimage.line = preimage.line_allocated;
        postimage.line = postimage.line_allocated;
 
@@ -2321,10 +2632,11 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
 
        if (applied_pos >= 0) {
                if (new_blank_lines_at_end &&
-                   preimage.nr + applied_pos == img->nr &&
+                   preimage.nr + applied_pos >= img->nr &&
                    (ws_rule & WS_BLANK_AT_EOF) &&
                    ws_error_action != nowarn_ws_error) {
-                       record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr);
+                       record_ws_error(WS_BLANK_AT_EOF, "+", 1,
+                                       found_new_blank_lines_at_end);
                        if (ws_error_action == correct_ws_error) {
                                while (new_blank_lines_at_end--)
                                        remove_last_line(&postimage);
@@ -2340,6 +2652,15 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                                apply = 0;
                }
 
+               if (apply_verbosely && applied_pos != pos) {
+                       int offset = applied_pos - pos;
+                       if (apply_in_reverse)
+                               offset = 0 - offset;
+                       fprintf(stderr,
+                               "Hunk #%d succeeded at %d (offset %d lines).\n",
+                               nth_fragment, applied_pos + 1, offset);
+               }
+
                /*
                 * Warn if it was necessary to reduce the number
                 * of context lines.
@@ -2357,7 +2678,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
        }
 
        free(oldlines);
-       free(newlines);
+       strbuf_release(&newlines);
        free(preimage.line_allocated);
        free(postimage.line_allocated);
 
@@ -2370,6 +2691,12 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
        unsigned long len;
        void *dst;
 
+       if (!fragment)
+               return error("missing binary patch data for '%s'",
+                            patch->new_name ?
+                            patch->new_name :
+                            patch->old_name);
+
        /* Binary patch is irreversible without the optional second hunk */
        if (apply_in_reverse) {
                if (!fragment->next)
@@ -2481,12 +2808,14 @@ static int apply_fragments(struct image *img, struct patch *patch)
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        unsigned ws_rule = patch->ws_rule;
        unsigned inaccurate_eof = patch->inaccurate_eof;
+       int nth = 0;
 
        if (patch->is_binary)
                return apply_binary(img, patch);
 
        while (frag) {
-               if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule)) {
+               nth++;
+               if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
                        error("patch failed: %s:%ld", name, frag->oldpos);
                        if (!apply_with_reject)
                                return -1;
@@ -2526,7 +2855,7 @@ static struct patch *in_fn_table(const char *name)
        if (name == NULL)
                return NULL;
 
-       item = string_list_lookup(name, &fn_table);
+       item = string_list_lookup(&fn_table, name);
        if (item != NULL)
                return (struct patch *)item->util;
 
@@ -2562,7 +2891,7 @@ static void add_to_fn_table(struct patch *patch)
         * file creations and copies
         */
        if (patch->new_name != NULL) {
-               item = string_list_insert(patch->new_name, &fn_table);
+               item = string_list_insert(&fn_table, patch->new_name);
                item->util = patch;
        }
 
@@ -2571,7 +2900,7 @@ static void add_to_fn_table(struct patch *patch)
         * later chunks shouldn't patch old names
         */
        if ((patch->new_name == NULL) || (patch->is_rename)) {
-               item = string_list_insert(patch->old_name, &fn_table);
+               item = string_list_insert(&fn_table, patch->old_name);
                item->util = PATH_WAS_DELETED;
        }
 }
@@ -2584,7 +2913,7 @@ static void prepare_fn_table(struct patch *patch)
        while (patch) {
                if ((patch->new_name == NULL) || (patch->is_rename)) {
                        struct string_list_item *item;
-                       item = string_list_insert(patch->old_name, &fn_table);
+                       item = string_list_insert(&fn_table, patch->old_name);
                        item->util = PATH_TO_BE_DELETED;
                }
                patch = patch->next;
@@ -2719,11 +3048,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
                if (stat_ret < 0) {
                        struct checkout costate;
                        /* checkout */
+                       memset(&costate, 0, sizeof(costate));
                        costate.base_dir = "";
-                       costate.base_dir_len = 0;
-                       costate.force = 0;
-                       costate.quiet = 0;
-                       costate.not_new = 0;
                        costate.refresh_cache = 1;
                        if (checkout_entry(*ce, &costate, NULL) ||
                            lstat(old_name, st))
@@ -2880,8 +3206,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
                else if (get_sha1(patch->old_sha1_prefix, sha1))
                        /* git diff has no index line for mode/type changes */
                        if (!patch->lines_added && !patch->lines_deleted) {
-                               if (get_current_sha1(patch->new_name, sha1) ||
-                                   get_current_sha1(patch->old_name, sha1))
+                               if (get_current_sha1(patch->old_name, sha1))
                                        die("mode change for %s, which is not "
                                                "in current HEAD", name);
                                sha1_ptr = sha1;
@@ -3039,11 +3364,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
                        die("unable to remove %s from index", patch->old_name);
        }
        if (!cached) {
-               if (S_ISGITLINK(patch->old_mode)) {
-                       if (rmdir(patch->old_name))
-                               warning("unable to remove submodule %s",
-                                       patch->old_name);
-               } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
+               if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
                        remove_path(patch->old_name);
                }
        }
@@ -3266,15 +3587,12 @@ static int write_out_one_reject(struct patch *patch)
        return -1;
 }
 
-static int write_out_results(struct patch *list, int skipped_patch)
+static int write_out_results(struct patch *list)
 {
        int phase;
        int errs = 0;
        struct patch *l;
 
-       if (!list && !skipped_patch)
-               return error("No changes");
-
        for (phase = 0; phase < 2; phase++) {
                l = list;
                while (l) {
@@ -3299,7 +3617,7 @@ static void add_name_limit(const char *name, int exclude)
 {
        struct string_list_item *it;
 
-       it = string_list_append(name, &limit_by_name);
+       it = string_list_append(&limit_by_name, name);
        it->util = exclude ? NULL : (void *) 1;
 }
 
@@ -3400,6 +3718,9 @@ static int apply_patch(int fd, const char *filename, int options)
                offset += nr;
        }
 
+       if (!list && !skipped_patch)
+               die("unrecognized input");
+
        if (whitespace_error && (ws_error_action == die_on_ws_error))
                apply = 0;
 
@@ -3417,7 +3738,7 @@ static int apply_patch(int fd, const char *filename, int options)
            !apply_with_reject)
                exit(1);
 
-       if (apply && write_out_results(list, skipped_patch))
+       if (apply && write_out_results(list))
                exit(1);
 
        if (fake_ancestor)
@@ -3512,12 +3833,11 @@ static int option_parse_directory(const struct option *opt,
        return 0;
 }
 
-int cmd_apply(int argc, const char **argv, const char *unused_prefix)
+int cmd_apply(int argc, const char **argv, const char *prefix_)
 {
        int i;
        int errs = 0;
-       int is_not_gitdir;
-       int binary;
+       int is_not_gitdir = !startup_info->have_repository;
        int force_apply = 0;
 
        const char *whitespace_option = NULL;
@@ -3536,12 +3856,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        "ignore additions made by the patch"),
                OPT_BOOLEAN(0, "stat", &diffstat,
                        "instead of applying the patch, output diffstat for the input"),
-               { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
-                 NULL, "old option, now no-op",
-                 PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
-               { OPTION_BOOLEAN, 0, "binary", &binary,
-                 NULL, "old option, now no-op",
-                 PARSE_OPT_HIDDEN | PARSE_OPT_NOARG },
+               OPT_NOOP_NOARG(0, "allow-binary-replacement"),
+               OPT_NOOP_NOARG(0, "binary"),
                OPT_BOOLEAN(0, "numstat", &numstat,
                        "shows number of added and deleted lines in decimal notation"),
                OPT_BOOLEAN(0, "summary", &summary,
@@ -3576,7 +3892,9 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        "don't expect at least one line of context"),
                OPT_BOOLEAN(0, "reject", &apply_with_reject,
                        "leave the rejected hunks in corresponding *.rej files"),
-               OPT__VERBOSE(&apply_verbosely),
+               OPT_BOOLEAN(0, "allow-overlap", &allow_overlap,
+                       "allow overlapping hunks"),
+               OPT__VERBOSE(&apply_verbosely, "be verbose"),
                OPT_BIT(0, "inaccurate-eof", &options,
                        "tolerate incorrectly detected missing new-line at the end of file",
                        INACCURATE_EOF),
@@ -3589,7 +3907,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                OPT_END()
        };
 
-       prefix = setup_git_directory_gently(&is_not_gitdir);
+       prefix = prefix_;
        prefix_length = prefix ? strlen(prefix) : 0;
        git_config(git_apply_config, NULL);
        if (apply_default_whitespace)