Browse Source

git-apply: pick up default filenames from "diff --git" header line

Pure mode changes, and deletes or creates of empty files won't have this
information anywhere else.
maint
Linus Torvalds 20 years ago
parent
commit
5041aa7040
  1. 82
      apply.c

82
apply.c

@ -36,7 +36,6 @@ static int max_change, max_len;
* things are flags, where -1 means "don't know yet". * things are flags, where -1 means "don't know yet".
*/ */
static int linenr = 1; static int linenr = 1;
static char *def_name = NULL;


struct fragment { struct fragment {
unsigned long oldpos, oldlines; unsigned long oldpos, oldlines;
@ -47,7 +46,7 @@ struct fragment {
}; };


struct patch { struct patch {
char *new_name, *old_name; char *new_name, *old_name, *def_name;
unsigned int old_mode, new_mode; unsigned int old_mode, new_mode;
int is_rename, is_copy, is_new, is_delete; int is_rename, is_copy, is_new, is_delete;
int lines_added, lines_deleted; int lines_added, lines_deleted;
@ -193,15 +192,15 @@ static void parse_traditional_patch(const char *first, const char *second, struc
if (is_dev_null(first)) { if (is_dev_null(first)) {
patch->is_new = 1; patch->is_new = 1;
patch->is_delete = 0; patch->is_delete = 0;
name = find_name(second, def_name, p_value, TERM_SPACE | TERM_TAB); name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB);
patch->new_name = name; patch->new_name = name;
} else if (is_dev_null(second)) { } else if (is_dev_null(second)) {
patch->is_new = 0; patch->is_new = 0;
patch->is_delete = 1; patch->is_delete = 1;
name = find_name(first, def_name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB); name = find_name(first, NULL, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
patch->old_name = name; patch->old_name = name;
} else { } else {
name = find_name(first, def_name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB); name = find_name(first, NULL, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
name = find_name(second, name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB); name = find_name(second, name, p_value, TERM_EXIST | TERM_SPACE | TERM_TAB);
patch->old_name = patch->new_name = name; patch->old_name = patch->new_name = name;
} }
@ -285,12 +284,14 @@ static int gitdiff_newmode(const char *line, struct patch *patch)
static int gitdiff_delete(const char *line, struct patch *patch) static int gitdiff_delete(const char *line, struct patch *patch)
{ {
patch->is_delete = 1; patch->is_delete = 1;
patch->old_name = patch->def_name;
return gitdiff_oldmode(line, patch); return gitdiff_oldmode(line, patch);
} }


static int gitdiff_newfile(const char *line, struct patch *patch) static int gitdiff_newfile(const char *line, struct patch *patch)
{ {
patch->is_new = 1; patch->is_new = 1;
patch->new_name = patch->def_name;
return gitdiff_newmode(line, patch); return gitdiff_newmode(line, patch);
} }


@ -336,6 +337,61 @@ static int gitdiff_unrecognized(const char *line, struct patch *patch)
return -1; return -1;
} }


static char *git_header_name(char *line)
{
int len;
char *name, *second;

/*
* Find the first '/'
*/
name = line;
for (;;) {
char c = *name++;
if (c == '\n')
return NULL;
if (c == '/')
break;
}

/*
* We don't accept absolute paths (/dev/null) as possibly valid
*/
if (name == line+1)
return NULL;

/*
* Accept a name only if it shows up twice, exactly the same
* form.
*/
for (len = 0 ; ; len++) {
char c = name[len];

switch (c) {
default:
continue;
case '\n':
break;
case '\t': case ' ':
second = name+len;
for (;;) {
char c = *second++;
if (c == '\n')
return NULL;
if (c == '/')
break;
}
if (!memcmp(name, second, len)) {
char *ret = xmalloc(len + 1);
memcpy(ret, name, len);
ret[len] = 0;
return ret;
}
}
}
return NULL;
}

/* Verify that we recognize the lines following a git header */ /* Verify that we recognize the lines following a git header */
static int parse_git_header(char *line, int len, unsigned int size, struct patch *patch) static int parse_git_header(char *line, int len, unsigned int size, struct patch *patch)
{ {
@ -345,6 +401,14 @@ static int parse_git_header(char *line, int len, unsigned int size, struct patch
patch->is_new = 0; patch->is_new = 0;
patch->is_delete = 0; patch->is_delete = 0;


/*
* Some things may not have the old name in the
* rest of the headers anywhere (pure mode changes,
* or removing or adding empty files), so we get
* the default name from the header.
*/
patch->def_name = git_header_name(line + strlen("diff --git "));

line += len; line += len;
size -= len; size -= len;
linenr++; linenr++;
@ -494,7 +558,8 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
int git_hdr_len = parse_git_header(line, len, size, patch); int git_hdr_len = parse_git_header(line, len, size, patch);
if (git_hdr_len < 0) if (git_hdr_len < 0)
continue; continue;

if (!patch->old_name && !patch->new_name)
die("git diff header lacks filename information");
*hdrsize = git_hdr_len; *hdrsize = git_hdr_len;
return offset; return offset;
} }
@ -630,11 +695,8 @@ static void show_stats(struct patch *patch)
char *name = patch->old_name; char *name = patch->old_name;
int len, max, add, del; int len, max, add, del;


if (!name) {
name = patch->new_name;
if (!name) if (!name)
return; name = patch->new_name;
}


/* /*
* "scale" the filename * "scale" the filename

Loading…
Cancel
Save