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;
* 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
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;
}
}
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)
#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;
- const char *name;
+ if (*name) {
+ int len = strlen(*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);
- another = find_name(line, NULL, p_value, TERM_TAB);
- if (!another || memcmp(another, name, len + 1))
+ die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
+ *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 {
+ } 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)
{
- 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);
+ 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)
{
- 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);
+ gitdiff_verify_name(line, patch->is_delete, &patch->new_name,
+ DIFF_NEW_NAME);
return 0;
}
{
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;
}
{
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;
}
{
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;
}
{
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;
}
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)
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 *);
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);
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)
"%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;
/* 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;
{
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);
}
/*
/* 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);
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;
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++;
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;
}
+/*
+ * 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)
{
/*
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;
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)
+ return -1;
if (used)
patchsize = used + llen;
else
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;
*/
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;
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 &&
}
/* 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++;
}
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,
* 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;
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)) {
listp = &patch->next;
}
else {
+ if (apply_verbosely)
+ say_patch_name(stderr, _("Skipped patch '%s'."), patch);
free_patch(patch);
skipped_patch++;
}
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;
}