builtin/apply: move 'read_stdin' global into cmd_apply()
[gitweb.git] / builtin / apply.c
index 8e4da2e1bdaf02590289f54750a9602281f4a365..c911e4ec8245ff06d9be4460b5041dee4428ec12 100644 (file)
@@ -35,7 +35,7 @@ static int prefix_length = -1;
 static int newfd = -1;
 
 static int unidiff_zero;
-static int p_value = 1;
+static int state_p_value = 1;
 static int p_value_known;
 static int check_index;
 static int update_index;
@@ -78,8 +78,6 @@ static enum ws_ignore {
 
 static const char *patch_input_file;
 static struct strbuf root = STRBUF_INIT;
-static int read_stdin = 1;
-static int options;
 
 static void parse_whitespace_option(const char *option)
 {
@@ -144,7 +142,7 @@ static int max_change, max_len;
  * file (and how) we're patching right now.. The "is_xxxx"
  * things are flags, where -1 means "don't know yet".
  */
-static int linenr = 1;
+static int state_linenr = 1;
 
 /*
  * This represents one "hunk" from a patch, starting with
@@ -872,24 +870,24 @@ static void parse_traditional_patch(const char *first, const char *second, struc
                q = guess_p_value(second);
                if (p < 0) p = q;
                if (0 <= p && p == q) {
-                       p_value = p;
+                       state_p_value = p;
                        p_value_known = 1;
                }
        }
        if (is_dev_null(first)) {
                patch->is_new = 1;
                patch->is_delete = 0;
-               name = find_name_traditional(second, NULL, p_value);
+               name = find_name_traditional(second, NULL, state_p_value);
                patch->new_name = name;
        } else if (is_dev_null(second)) {
                patch->is_new = 0;
                patch->is_delete = 1;
-               name = find_name_traditional(first, NULL, p_value);
+               name = find_name_traditional(first, NULL, state_p_value);
                patch->old_name = name;
        } else {
                char *first_name;
-               first_name = find_name_traditional(first, NULL, p_value);
-               name = find_name_traditional(second, first_name, p_value);
+               first_name = find_name_traditional(first, NULL, state_p_value);
+               name = find_name_traditional(second, first_name, state_p_value);
                free(first_name);
                if (has_epoch_timestamp(first)) {
                        patch->is_new = 1;
@@ -905,7 +903,7 @@ static void parse_traditional_patch(const char *first, const char *second, struc
                }
        }
        if (!name)
-               die(_("unable to find filename in patch at line %d"), linenr);
+               die(_("unable to find filename in patch at line %d"), state_linenr);
 }
 
 static int gitdiff_hdrend(const char *line, struct patch *patch)
@@ -925,43 +923,43 @@ static int gitdiff_hdrend(const char *line, struct patch *patch)
 #define DIFF_OLD_NAME 0
 #define DIFF_NEW_NAME 1
 
-static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, int side)
+static void gitdiff_verify_name(const char *line, int isnull, char **name, int side)
 {
-       if (!orig_name && !isnull)
-               return find_name(line, NULL, p_value, TERM_TAB);
+       if (!*name && !isnull) {
+               *name = find_name(line, NULL, state_p_value, TERM_TAB);
+               return;
+       }
 
-       if (orig_name) {
-               int len = strlen(orig_name);
+       if (*name) {
+               int len = strlen(*name);
                char *another;
                if (isnull)
                        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, orig_name, len + 1))
+                           *name, state_linenr);
+               another = find_name(line, NULL, state_p_value, TERM_TAB);
+               if (!another || memcmp(another, *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);
+                           _("git apply: bad git-diff - inconsistent old filename on line %d"), state_linenr);
                free(another);
-               return orig_name;
        } 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);
-               return NULL;
+                       die(_("git apply: bad git-diff - expected /dev/null on line %d"), state_linenr);
        }
 }
 
 static int gitdiff_oldname(const char *line, struct patch *patch)
 {
-       patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name,
-                                             DIFF_OLD_NAME);
+       gitdiff_verify_name(line, patch->is_new, &patch->old_name,
+                           DIFF_OLD_NAME);
        return 0;
 }
 
 static int gitdiff_newname(const char *line, struct patch *patch)
 {
-       patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name,
-                                             DIFF_NEW_NAME);
+       gitdiff_verify_name(line, patch->is_delete, &patch->new_name,
+                           DIFF_NEW_NAME);
        return 0;
 }
 
@@ -997,7 +995,7 @@ static int gitdiff_copysrc(const char *line, struct patch *patch)
 {
        patch->is_copy = 1;
        free(patch->old_name);
-       patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+       patch->old_name = find_name(line, NULL, state_p_value ? state_p_value - 1 : 0, 0);
        return 0;
 }
 
@@ -1005,7 +1003,7 @@ static int gitdiff_copydst(const char *line, struct patch *patch)
 {
        patch->is_copy = 1;
        free(patch->new_name);
-       patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+       patch->new_name = find_name(line, NULL, state_p_value ? state_p_value - 1 : 0, 0);
        return 0;
 }
 
@@ -1013,7 +1011,7 @@ static int gitdiff_renamesrc(const char *line, struct patch *patch)
 {
        patch->is_rename = 1;
        free(patch->old_name);
-       patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+       patch->old_name = find_name(line, NULL, state_p_value ? state_p_value - 1 : 0, 0);
        return 0;
 }
 
@@ -1021,7 +1019,7 @@ static int gitdiff_renamedst(const char *line, struct patch *patch)
 {
        patch->is_rename = 1;
        free(patch->new_name);
-       patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0);
+       patch->new_name = find_name(line, NULL, state_p_value ? state_p_value - 1 : 0, 0);
        return 0;
 }
 
@@ -1092,10 +1090,10 @@ static const char *skip_tree_prefix(const char *line, int llen)
        int nslash;
        int i;
 
-       if (!p_value)
+       if (!state_p_value)
                return (llen && line[0] == '/') ? NULL : line;
 
-       nslash = p_value;
+       nslash = state_p_value;
        for (i = 0; i < llen; i++) {
                int ch = line[i];
                if (ch == '/' && --nslash <= 0)
@@ -1272,8 +1270,8 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct
 
        line += len;
        size -= len;
-       linenr++;
-       for (offset = len ; size > 0 ; offset += len, size -= len, line += len, linenr++) {
+       state_linenr++;
+       for (offset = len ; size > 0 ; offset += len, size -= len, line += len, state_linenr++) {
                static const struct opentry {
                        const char *str;
                        int (*fn)(const char *, struct patch *);
@@ -1440,7 +1438,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
        patch->is_new = patch->is_delete = -1;
        patch->old_mode = patch->new_mode = 0;
        patch->old_name = patch->new_name = NULL;
-       for (offset = 0; size > 0; offset += len, size -= len, line += len, linenr++) {
+       for (offset = 0; size > 0; offset += len, size -= len, line += len, state_linenr++) {
                unsigned long nextlen;
 
                len = linelen(line, size);
@@ -1461,7 +1459,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
                        if (parse_fragment_header(line, len, &dummy) < 0)
                                continue;
                        die(_("patch fragment without header at line %d: %.*s"),
-                           linenr, (int)len-1, line);
+                           state_linenr, (int)len-1, line);
                }
 
                if (size < len + 6)
@@ -1481,14 +1479,14 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
                                               "%d leading pathname component (line %d)",
                                               "git diff header lacks filename information when removing "
                                               "%d leading pathname components (line %d)",
-                                              p_value),
-                                           p_value, linenr);
+                                              state_p_value),
+                                           state_p_value, state_linenr);
                                patch->old_name = xstrdup(patch->def_name);
                                patch->new_name = xstrdup(patch->def_name);
                        }
                        if (!patch->is_delete && !patch->new_name)
                                die("git diff header lacks filename information "
-                                   "(line %d)", linenr);
+                                   "(line %d)", state_linenr);
                        patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
@@ -1510,7 +1508,7 @@ static int find_header(const char *line, unsigned long size, int *hdrsize, struc
                /* Ok, we'll consider it a patch */
                parse_traditional_patch(line, line+len, patch);
                *hdrsize = len + nextlen;
-               linenr += 2;
+               state_linenr += 2;
                return offset;
        }
        return -1;
@@ -1538,7 +1536,7 @@ static void check_whitespace(const char *line, int len, unsigned ws_rule)
 {
        unsigned result = ws_check(line + 1, len - 1, ws_rule);
 
-       record_ws_error(result, line + 1, len - 2, linenr);
+       record_ws_error(result, line + 1, len - 2, state_linenr);
 }
 
 /*
@@ -1568,11 +1566,11 @@ static int parse_fragment(const char *line, unsigned long size,
        /* Parse the thing.. */
        line += len;
        size -= len;
-       linenr++;
+       state_linenr++;
        added = deleted = 0;
        for (offset = len;
             0 < size;
-            offset += len, size -= len, line += len, linenr++) {
+            offset += len, size -= len, line += len, state_linenr++) {
                if (!oldlines && !newlines)
                        break;
                len = linelen(line, size);
@@ -1668,10 +1666,10 @@ static int parse_single_patch(const char *line, unsigned long size, struct patch
                int len;
 
                fragment = xcalloc(1, sizeof(*fragment));
-               fragment->linenr = linenr;
+               fragment->linenr = state_linenr;
                len = parse_fragment(line, size, patch, fragment);
                if (len <= 0)
-                       die(_("corrupt patch at line %d"), linenr);
+                       die(_("corrupt patch at line %d"), state_linenr);
                fragment->patch = line;
                fragment->size = len;
                oldlines += fragment->oldlines;
@@ -1799,13 +1797,13 @@ static struct fragment *parse_binary_hunk(char **buf_p,
        else
                return NULL;
 
-       linenr++;
+       state_linenr++;
        buffer += llen;
        while (1) {
                int byte_length, max_byte_length, newsize;
                llen = linelen(buffer, size);
                used += llen;
-               linenr++;
+               state_linenr++;
                if (llen == 1) {
                        /* consume the blank line */
                        buffer++;
@@ -1859,7 +1857,7 @@ static struct fragment *parse_binary_hunk(char **buf_p,
        free(data);
        *status_p = -1;
        error(_("corrupt binary patch at line %d: %.*s"),
-             linenr-1, llen-1, buffer);
+             state_linenr-1, llen-1, buffer);
        return NULL;
 }
 
@@ -1892,7 +1890,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
        forward = parse_binary_hunk(&buffer, &size, &status, &used);
        if (!forward && !status)
                /* there has to be one hunk (forward hunk) */
-               return error(_("unrecognized binary patch at line %d"), linenr-1);
+               return error(_("unrecognized binary patch at line %d"), state_linenr-1);
        if (status)
                /* otherwise we already gave an error message */
                return status;
@@ -2010,7 +2008,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
                if (llen == sizeof(git_binary) - 1 &&
                    !memcmp(git_binary, buffer + hd, llen)) {
                        int used;
-                       linenr++;
+                       state_linenr++;
                        used = parse_binary(buffer + hd + llen,
                                            size - hd - llen, patch);
                        if (used < 0)
@@ -2031,7 +2029,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
                                int len = strlen(binhdr[i]);
                                if (len < size - hd &&
                                    !memcmp(binhdr[i], buffer + hd, len)) {
-                                       linenr++;
+                                       state_linenr++;
                                        patch->is_binary = 1;
                                        patchsize = llen;
                                        break;
@@ -2045,7 +2043,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
                 */
                if ((apply || check) &&
                    (!patch->is_binary && !metadata_changes(patch)))
-                       die(_("patch with only garbage at line %d"), linenr);
+                       die(_("patch with only garbage at line %d"), state_linenr);
        }
 
        return offset + hdrsize + patchsize;
@@ -2194,17 +2192,17 @@ static void update_pre_post_images(struct image *preimage,
        fixed = preimage->buf;
 
        for (i = reduced = ctx = 0; i < postimage->nr; i++) {
-               size_t len = postimage->line[i].len;
+               size_t l_len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
-                       memmove(new, old, len);
-                       old += len;
-                       new += len;
+                       memmove(new, old, l_len);
+                       old += l_len;
+                       new += l_len;
                        continue;
                }
 
                /* a common context -- skip it in the original postimage */
-               old += len;
+               old += l_len;
 
                /* and find the corresponding one in the fixed preimage */
                while (ctx < preimage->nr &&
@@ -2223,11 +2221,11 @@ static void update_pre_post_images(struct image *preimage,
                }
 
                /* and copy it in, while fixing the line length */
-               len = preimage->line[ctx].len;
-               memcpy(new, fixed, len);
-               new += len;
-               fixed += len;
-               postimage->line[i].len = len;
+               l_len = preimage->line[ctx].len;
+               memcpy(new, fixed, l_len);
+               new += l_len;
+               fixed += l_len;
+               postimage->line[i].len = l_len;
                ctx++;
        }
 
@@ -2242,6 +2240,74 @@ static void update_pre_post_images(struct image *preimage,
        postimage->nr -= reduced;
 }
 
+static int line_by_line_fuzzy_match(struct image *img,
+                                   struct image *preimage,
+                                   struct image *postimage,
+                                   unsigned long try,
+                                   int try_lno,
+                                   int preimage_limit)
+{
+       int i;
+       size_t imgoff = 0;
+       size_t preoff = 0;
+       size_t postlen = postimage->len;
+       size_t extra_chars;
+       char *buf;
+       char *preimage_eof;
+       char *preimage_end;
+       struct strbuf fixed;
+       char *fixed_buf;
+       size_t fixed_len;
+
+       for (i = 0; i < preimage_limit; i++) {
+               size_t prelen = preimage->line[i].len;
+               size_t imglen = img->line[try_lno+i].len;
+
+               if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
+                                     preimage->buf + preoff, prelen))
+                       return 0;
+               if (preimage->line[i].flag & LINE_COMMON)
+                       postlen += imglen - prelen;
+               imgoff += imglen;
+               preoff += prelen;
+       }
+
+       /*
+        * 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.)
+        */
+       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 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, fixed_len, postlen);
+       return 1;
+}
+
 static int match_fragment(struct image *img,
                          struct image *preimage,
                          struct image *postimage,
@@ -2331,61 +2397,9 @@ static int match_fragment(struct image *img,
         * fuzzy matching. We collect all the line length information because
         * we need it to adjust whitespace if we match.
         */
-       if (ws_ignore_action == ignore_ws_change) {
-               size_t imgoff = 0;
-               size_t preoff = 0;
-               size_t postlen = postimage->len;
-               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;
-
-                       if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
-                                             preimage->buf + preoff, prelen))
-                               return 0;
-                       if (preimage->line[i].flag & LINE_COMMON)
-                               postlen += imglen - prelen;
-                       imgoff += imglen;
-                       preoff += prelen;
-               }
-
-               /*
-                * 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.)
-                */
-               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 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, fixed_len, postlen);
-               return 1;
-       }
+       if (ws_ignore_action == ignore_ws_change)
+               return line_by_line_fuzzy_match(img, preimage, postimage,
+                                               try, try_lno, preimage_limit);
 
        if (ws_error_action != correct_ws_error)
                return 0;
@@ -4461,7 +4475,7 @@ static int option_parse_include(const struct option *opt,
 static int option_parse_p(const struct option *opt,
                          const char *arg, int unset)
 {
-       p_value = atoi(arg);
+       state_p_value = atoi(arg);
        p_value_known = 1;
        return 0;
 }
@@ -4501,6 +4515,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
        int errs = 0;
        int is_not_gitdir = !startup_info->have_repository;
        int force_apply = 0;
+       int options = 0;
+       int read_stdin = 1;
 
        const char *whitespace_option = NULL;