struct string_list limit_by_name;
int has_include;
+ /* Various "current state" */
+ int linenr; /* current line number */
+
/*
* For "diff-stat" like behaviour, we keep track of the biggest change
* we've seen, and the longest filename. That allows us to do simple
int max_change;
int max_len;
+ /*
+ * Records filenames that have been touched, in order to handle
+ * the case where more than one patches touch the same file.
+ */
+ struct string_list fn_table;
+
/* These control whitespace errors */
enum ws_error_action ws_error_action;
enum ws_ignore ws_ignore_action;
state->ws_error_action = (state->apply ? warn_on_ws_error : nowarn_ws_error);
}
-/*
- * Various "current state", notably line numbers and what
- * file (and how) we're patching right now.. The "is_xxxx"
- * things are flags, where -1 means "don't know yet".
- */
-static int state_linenr = 1;
-
/*
* This represents one "hunk" from a patch, starting with
* "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
struct line *line;
};
-/*
- * Records filenames that have been touched, in order to handle
- * the case where more than one patches touch the same file.
- */
-
-static struct string_list fn_table;
-
static uint32_t hash_line(const char *cp, size_t len)
{
size_t i;
}
}
if (!name)
- die(_("unable to find filename in patch at line %d"), state_linenr);
+ die(_("unable to find filename in patch at line %d"), state->linenr);
}
static int gitdiff_hdrend(struct apply_state *state,
char *another;
if (isnull)
die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
- *name, state_linenr);
+ *name, state->linenr);
another = find_name(state, 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"), state_linenr);
+ _("git apply: bad git-diff - inconsistent old filename on line %d"), state->linenr);
free(another);
} 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"), state_linenr);
+ die(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
}
}
line += len;
size -= len;
- state_linenr++;
- for (offset = len ; size > 0 ; offset += len, size -= len, line += len, state_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)(struct apply_state *, 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, state_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"),
- state_linenr, (int)len-1, line);
+ state->linenr, (int)len-1, line);
}
if (size < len + 6)
"git diff header lacks filename information when removing "
"%d leading pathname components (line %d)",
state->p_value),
- state->p_value, state_linenr);
+ 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)", state_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(state, line, line+len, patch);
*hdrsize = len + nextlen;
- state_linenr += 2;
+ state->linenr += 2;
return offset;
}
return -1;
{
unsigned result = ws_check(line + 1, len - 1, ws_rule);
- record_ws_error(state, result, line + 1, len - 2, state_linenr);
+ record_ws_error(state, result, line + 1, len - 2, state->linenr);
}
/*
/* Parse the thing.. */
line += len;
size -= len;
- state_linenr++;
+ state->linenr++;
added = deleted = 0;
for (offset = len;
0 < size;
- offset += len, size -= len, line += len, state_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 = state_linenr;
+ fragment->linenr = state->linenr;
len = parse_fragment(state, line, size, patch, fragment);
if (len <= 0)
- die(_("corrupt patch at line %d"), state_linenr);
+ die(_("corrupt patch at line %d"), state->linenr);
fragment->patch = line;
fragment->size = len;
oldlines += fragment->oldlines;
* points at an allocated memory that the caller must free, so
* it is marked as "->free_patch = 1".
*/
-static struct fragment *parse_binary_hunk(char **buf_p,
+static struct fragment *parse_binary_hunk(struct apply_state *state,
+ char **buf_p,
unsigned long *sz_p,
int *status_p,
int *used_p)
else
return NULL;
- state_linenr++;
+ state->linenr++;
buffer += llen;
while (1) {
int byte_length, max_byte_length, newsize;
llen = linelen(buffer, size);
used += llen;
- state_linenr++;
+ state->linenr++;
if (llen == 1) {
/* consume the blank line */
buffer++;
free(data);
*status_p = -1;
error(_("corrupt binary patch at line %d: %.*s"),
- state_linenr-1, llen-1, buffer);
+ state->linenr-1, llen-1, buffer);
return NULL;
}
* -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)
+static int parse_binary(struct apply_state *state,
+ char *buffer,
+ unsigned long size,
+ struct patch *patch)
{
/*
* We have read "GIT binary patch\n"; what follows is a line
int status;
int used, used_1;
- forward = parse_binary_hunk(&buffer, &size, &status, &used);
+ forward = parse_binary_hunk(state, &buffer, &size, &status, &used);
if (!forward && !status)
/* there has to be one hunk (forward hunk) */
- return error(_("unrecognized binary patch at line %d"), state_linenr-1);
+ return error(_("unrecognized binary patch at line %d"), state->linenr-1);
if (status)
/* otherwise we already gave an error message */
return status;
- reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
+ reverse = parse_binary_hunk(state, &buffer, &size, &status, &used_1);
if (reverse)
used += used_1;
else if (status) {
if (llen == sizeof(git_binary) - 1 &&
!memcmp(git_binary, buffer + hd, llen)) {
int used;
- state_linenr++;
- used = parse_binary(buffer + hd + llen,
+ state->linenr++;
+ used = parse_binary(state, buffer + hd + llen,
size - hd - llen, patch);
if (used < 0)
return -1;
int len = strlen(binhdr[i]);
if (len < size - hd &&
!memcmp(binhdr[i], buffer + hd, len)) {
- state_linenr++;
+ state->linenr++;
patch->is_binary = 1;
patchsize = llen;
break;
*/
if ((state->apply || state->check) &&
(!patch->is_binary && !metadata_changes(patch)))
- die(_("patch with only garbage at line %d"), state_linenr);
+ die(_("patch with only garbage at line %d"), state->linenr);
}
return offset + hdrsize + patchsize;
return read_blob_object(buf, ce->sha1, ce->ce_mode);
}
-static struct patch *in_fn_table(const char *name)
+static struct patch *in_fn_table(struct apply_state *state, const char *name)
{
struct string_list_item *item;
if (name == NULL)
return NULL;
- item = string_list_lookup(&fn_table, name);
+ item = string_list_lookup(&state->fn_table, name);
if (item != NULL)
return (struct patch *)item->util;
return patch == PATH_WAS_DELETED;
}
-static void add_to_fn_table(struct patch *patch)
+static void add_to_fn_table(struct apply_state *state, struct patch *patch)
{
struct string_list_item *item;
* file creations and copies
*/
if (patch->new_name != NULL) {
- item = string_list_insert(&fn_table, patch->new_name);
+ item = string_list_insert(&state->fn_table, patch->new_name);
item->util = patch;
}
* later chunks shouldn't patch old names
*/
if ((patch->new_name == NULL) || (patch->is_rename)) {
- item = string_list_insert(&fn_table, patch->old_name);
+ item = string_list_insert(&state->fn_table, patch->old_name);
item->util = PATH_WAS_DELETED;
}
}
-static void prepare_fn_table(struct patch *patch)
+static void prepare_fn_table(struct apply_state *state, struct patch *patch)
{
/*
* store information about incoming file deletion
while (patch) {
if ((patch->new_name == NULL) || (patch->is_rename)) {
struct string_list_item *item;
- item = string_list_insert(&fn_table, patch->old_name);
+ item = string_list_insert(&state->fn_table, patch->old_name);
item->util = PATH_TO_BE_DELETED;
}
patch = patch->next;
return 0;
}
-static struct patch *previous_patch(struct patch *patch, int *gone)
+static struct patch *previous_patch(struct apply_state *state,
+ struct patch *patch,
+ int *gone)
{
struct patch *previous;
if (patch->is_copy || patch->is_rename)
return NULL; /* "git" patches do not depend on the order */
- previous = in_fn_table(patch->old_name);
+ previous = in_fn_table(state, patch->old_name);
if (!previous)
return NULL;
struct patch *previous;
int status;
- previous = previous_patch(patch, &status);
+ previous = previous_patch(state, patch, &status);
if (status)
return error(_("path %s has been renamed/deleted"),
patch->old_name);
}
patch->result = image.buf;
patch->resultsize = image.len;
- add_to_fn_table(patch);
+ add_to_fn_table(state, patch);
free(image.line_allocated);
if (0 < patch->is_delete && patch->resultsize)
return 0;
assert(patch->is_new <= 0);
- previous = previous_patch(patch, &status);
+ previous = previous_patch(state, patch, &status);
if (status)
return error(_("path %s has been renamed/deleted"), old_name);
* B and rename from A to B is handled the same way by asking
* was_deleted().
*/
- if ((tpatch = in_fn_table(new_name)) &&
+ if ((tpatch = in_fn_table(state, new_name)) &&
(was_deleted(tpatch) || to_be_deleted(tpatch)))
ok_if_exists = 1;
else
int err = 0;
prepare_symlink_changes(patch);
- prepare_fn_table(patch);
+ prepare_fn_table(state, patch);
while (patch) {
if (state->apply_verbosely)
say_patch_name(stderr,
free_patch_list(list);
strbuf_release(&buf);
- string_list_clear(&fn_table, 0);
+ string_list_clear(&state->fn_table, 0);
return 0;
}
state->squelch_whitespace_errors = 5;
state->ws_error_action = warn_on_ws_error;
state->ws_ignore_action = ignore_ws_none;
+ state->linenr = 1;
strbuf_init(&state->root, 0);
git_apply_config();
{
string_list_clear(&state->limit_by_name, 0);
strbuf_release(&state->root);
+
+ /* &state->fn_table is cleared at the end of apply_patch() */
}
int cmd_apply(int argc, const char **argv, const char *prefix)